------- android培训、java培训、期待与您交流! ----------
>>类加载器
Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader
类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是不是java类,这正是BootStrap。它是用C++语言写的,嵌套在内核中的一段代码。
Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。
eg:演示层级关系
package com.classLoader;
public class ClassLoaderDemo {
publicstatic void main(String[] args) {
ClassLoaderloader = ClassLoaderDemo.class.getClassLoader();
while(loader!= null)
{
System.out.println(loader.getClass().getName());
loader= loader.getParent();
}
System.out.println(loader);
}
}
输出:
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null
如果在ext文件夹和classpath中都有相同的类,那么就有优先加载的问题。一般由ExtClassLoader加载。这就涉及“类加载器的委托机制”。
当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
1) 首先当前线程的类加载器去加载线程中的第一个类。
在Thread中有方法:
publicvoid setContextClassLoader(ClassLoader cl)
设置该线程的上下文ClassLoader。上下文 ClassLoader 可以在创建线程设置,并允许创建者在加载类和资源时向该线程中运行的代码提供适当的类加载器。
首先,如果有安全管理器,则通过 RuntimePermission("setContextClassLoader") 权限调用其checkPermission 方法,查看是否可以设置上下文 ClassLoader。
2)如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
3)还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
每个类加载器加载类时,又先委托给其上级类加载器。
1)当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?
2)对着类加载器的层次结构图和委托加载原理,就可以解释将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。
有一道面试,能不能自己写个类叫java.lang.System,为了不让我们写System类,类加载采用委托机制,这样可以保证爸爸们优先,也就是总是使用爸爸们能找到的类,这样总是使用java系统提供的System。
把先前编写的类加入到jdk的rt.jar中,会有怎样的效果呢?不行!!!看来是不能随意将自己的class文件加入进rt.jar文件中的。
>>自定义类加载器
1)自定义的类加载器的必须继承ClassLoader
2)ClassLoader中有loadClass方法与findClass方法
3)defineClass方法
编程步骤:
1)编写一个对文件内容进行简单加密的程序。
2)编写了一个自己的类装载器,可实现对加密过的类进行装载和解密。
3)编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类。程序中可以除了使用ClassLoader.load方法之外,还可以使用设置线程的上下文类加载器或者系统类加载器,然后再使用Class.forName。
实验步骤:
1)对不带包名的class文件进行加密,加密结果存放到另外一个目录,例如: java MyClassLoader MyTest.class F:\itcast
2)运行加载类的程序,结果能够被正常加载,但打印出来的类装载器名称为AppClassLoader:java MyClassLoader MyTest F:\itcast
3)用加密后的类文件替换CLASSPATH环境下的类文件,再执行上一步操作就出问题了,错误说明是AppClassLoader类装载器装载失败。
4)删除CLASSPATH环境下的类文件,再执行上一步操作就没问题了。
上述说明引出自定义类加载器的原理,首先继承ClassLoader,其中有loadClass方法与findClass方法。我们要保留loadClass方法,覆盖findClass方法。如果加载器使用loadClass方法去访问父类(父加载器)找不到要加载的类,那么就会调用findClass方法。而后会调用defineClass方法获得被加载类的字节码。
loadClass
protected Class> loadClass(Stringname, boolean resolve)
throwsClassNotFoundException使用指定的二进制名称来加载类。此方法的默认实现将按以下顺序搜索类:
1、调用findLoadedClass(String) 来检查是否已经加载类。
2、在父类加载器上调用 loadClass 方法。如果父类加载器为null,则使用虚拟机的内置类加载器。
3、调用 findClass(String)方法查找类。
如果使用上述步骤找到类,并且resolve 标志为真,则此方法将在得到的 Class 对象上调用 resolveClass(Class) 方法。鼓励用 ClassLoader 的子类重写 findClass(String),而不是使用此方法。
findClass
protected Class> findClass(Stringname) throws ClassNotFoundException
使用指定的二进制名称查找类。此方法应该被类加载器的实现重写,该实现按照委托模型来加载类。在通过父类加载器检查所请求的类后,此方法将被 loadClass 方法调用。默认实现抛出一个 ClassNotFoundException。
eg:自定义类加载器
import java.io.*;
import java.lang.reflect.*;
public class MyClassLoader extendsClassLoader
{
privateString path = null;
publicMyClassLoader(String path) throws Exception//检查文件是否存在
{
Filef = new File(path);
if(!f.isDirectory())
{
thrownew RuntimeException(path + " is not a directory");
}
this.path= path;
}
publicClass findClass(String name) //throws Exception //为什么不能抛出
{
try
{
Filef = new File(path,name.substring(name.lastIndexOf('.')+1) +".class");
FileInputStreamfis = new FileInputStream(f);
ByteArrayOutputStreambos = new ByteArrayOutputStream();
cypher(fis,bos);
byte[] buf = bos.toByteArray();
fis.close();
bos.close();
returndefineClass(name,buf,0,buf.length);
}
catch(Exception e)
{
//子类方法不能比父类抛出更多的异常
thrownew ClassNotFoundException(name + " is not found!");
}
returnnull;
}
publicstatic void cypher(InputStream istream,OutputStream ostream) throws Exception
{
//下面这段代码可能遇到255的字节,当成byte就成了-1
/*byteb = 0;
while((b= (byte)istream.read()) != -1)
{
ostream.write(b^ 0xff);
}*/
intb = 0;
while((b= istream.read()) != -1)
{
ostream.write(((byte)b)^ 0xff);
}
}
publicstatic void main(String [] args) throws Exception
{
//下面省略了错误检查
if(!args[0].endsWith("class"))
{
ClassLoaderloader = new MyClassLoader(args[1]);
Classcls = loader.loadClass(args[0]);
/*
让自定义类继承Date类
System.out.println(cls.getClassLoader().getClass().getName());
java.util.Dated = (java.util.Date)cls.newInstance();
System.out.println(d.toString());
*/
//Methodm = cls.getMethod("test",null);//在jdk1.5中报警告,为什么?
Methodm = cls.getMethod("test");
//m.invoke(cls.newInstance(),null);
m.invoke(cls.newInstance());
//((Test)cls.newInstance()).test();
return;
}
else
{
FileInputStreamfis = new FileInputStream(args[0]);
Filef = new File(args[1], new File(args[0]).getName());
//不用检查目录最后是否有目录分割符
FileOutputStreamfos = new FileOutputStream(f);
cypher(fis,fos);
fis.close();
fos.close();
}
}
}
//类加载器不能加载这种非public的类
/*
Exception in thread "main"java.lang.IllegalAccessException: Class MyClassLoader
cannot access a member of class MyTest with modifiers ""
*/
/*
class MyTest
{
publicvoid test()
{
System.out.println("hello,www.it315.org");
}
}
*/
>>类加载器一个高级问题分析
eg:使用web工程演示tomcat的加载器
package com.cty;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet{
/**
* Constructor of the object.
*/
publicMyServlet() {
super();
}
publicvoid doGet(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {
response.setContentType("text/html");
PrintWriterout = response.getWriter();
//获得servlet类加载器
ClassLoadercl = this.getClass().getClassLoader();
while(cl!= null)
{
//输出到浏览器
out.println(cl.getClass().getName()+ "
");
cl= cl.getParent();
}
out.close();
}
}
/*
浏览器输出:
org.apache.catalina.loader.WebappClassLoader
org.apache.catalina.loader.StandardClassLoader
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
*/
把MyServlet.class文件打jar包,放到ext目录中,重启tomcat,发现找不到HttpServlet的错误。
(将tomcat运行的jre配置下
MyServlet.class文件打的jar包要放在和tomcat运行的jdk同一个版本下)
ext找到了myServlet,但是myServlet继承了HttpServlet,导致ExtClassLoader加载器还要去找HttpServlet,所以查找失败。解决这个问题,就把HttpServlet所在的jar包(tomcata提供的servlet-api.jar)放到ext目录中即可。
父级类加载器加载的类无法引用只能被子级类加载器加载的类。
>>代理的概念与作用
程序中的代理
1)要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事务管理、等等,你准备如何做?
2)编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。(参看下页的原理图)
3)如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易
>>AOP
比如,一个系统中有很多模块,但是这些模块又都有安全、事务管理、日志等功能,所以,它们称为交叉业务。
安全 事务 日志
StudentService ------|----------|------------|-------------
CourseService ------|----------|------------|-------------
MiscService ------|----------|------------|-------------
一般,我们把这些业务描述在方法体中:
method1 method2 method3
{ { {
------------------------------------------------------切面
.... .... ......
------------------------------------------------------切面
} } }
交叉业务的编程问题即为面向切面的编程(Aspectoriented program ,简称AOP)。AOP的目标就是要使交叉业务模块化。可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的,如下所示:
------------------------------------------------------切面
func1 func2 func3
{ { {
.... .... ......
} } }
------------------------------------------------------切面
使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。
>>动态代理技术
要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!写成百上千个代理类,是不是太累!
JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
CGLIB库(第三方,非标准)可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中
>>分析JVM动态生成的类
eg:输出动态生成类中的一些信息
package com.proxy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
public class ProxyTest {
/**
* 验证JVM动态生成的类
*/
publicstatic void main(String[] args) {
ClassclazzProxy =
Proxy.getProxyClass(Collection.class.getClassLoader(),
Collection.class);
System.out.println(clazzProxy.getName());
//输出构造函数
System.out.println("---Beginconstructors list---");
Constructor[]constructors = clazzProxy.getConstructors();
for(Constructorconstructor : constructors)
{
//StringBuffer和StringBuild有什么区别呢?
//应用上几乎是一样的,但是StringBuffer更适合多线程,它考虑了安全问题,效率较低
StringcName = constructor.getName();
StringBuildersBuilder = new StringBuilder(cName);
//格式化输出
sBuilder.append("(");
Class[]clazzParams = constructor.getParameterTypes();
for(ClassclazzParam : clazzParams)
{
sBuilder.append(clazzParam.getName()).append(',');
}
if(clazzParams!= null && clazzParams.length != 0)
{
sBuilder.deleteCharAt(sBuilder.length()-1);
}
sBuilder.append(")");
System.out.println(sBuilder.toString());
}
//输出方法列表
System.out.println("---BeginMethod list---");
Method[]methods = clazzProxy.getMethods();
for(Methodmethod : methods)
{
//StringBuffer和StringBuild有什么区别呢?
//应用上几乎是一样的,但是StringBuffer更适合多线程,它考虑了安全问题,效率较低
StringcName = method.getName();
StringBuildersBuilder = new StringBuilder(cName);
//格式化输出
sBuilder.append("(");
Class[]clazzParams = method.getParameterTypes();
for(ClassclazzParam : clazzParams)
{
sBuilder.append(clazzParam.getName()).append(',');
}
if(clazzParams!= null && clazzParams.length != 0)
{
sBuilder.deleteCharAt(sBuilder.length()-1);
}
sBuilder.append(")");
System.out.print(sBuilder.toString());
System.out.print("| "); }
}
}
输出:
$Proxy0
---Begin constructors list---
$Proxy0(java.lang.reflect.InvocationHandler)
---Begin Method list---
add(java.lang.Object) |equals(java.lang.Object) | toString() | hashCode() | clear() |
contains(java.lang.Object) | isEmpty() | addAll(java.util.Collection)| iterator() | size() |
toArray([Ljava.lang.Object;) | toArray() |remove(java.lang.Object) |
containsAll(java.util.Collection) |removeAll(java.util.Collection) | retainAll(java.util.Collection) |
isProxyClass(java.lang.Class) |getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;) |
getInvocationHandler(java.lang.Object) |
newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)|
wait(long) | wait() | wait(long,int) |getClass() | notify() | notifyAll() |
eg:动态代理生成实例
package com.proxy;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
public class ProxyInstanceDemo {
publicstatic void main(String[] args) throws Exception {
ClassproxyClass = Proxy.getProxyClass(Collection.class
.getClassLoader(),Collection.class);
//报错,都和你说了生成的动态类没有无参构造函数了嘛
//Object obj = proxyClass.newInstance();
Constructorconstructor = proxyClass
.getConstructor(InvocationHandler.class);
//使用匿名内部类传入参数
Collectionpid = (Collection) constructor
.newInstance(newInvocationHandler() {
publicObject invoke(Object arg0, Method arg1, Object[] arg2)
throwsThrowable {
//演示用,返回空
returnnull;
}
});
//生成类了吗?
System.out.println(pid.toString());//输出"null",如果没有生成类会空指针异常
System.out.println(pid.getClass());
/*输出:
null
class$Proxy0*/
}
}
总结:以上过程
1)创建动态类的实例对象
2)用反射获得构造方法
3)编写一个最简单的InvocationHandler类
4)调用构造方法创建动态类的实例对象,并将编写的InvocationHandler类的实例对象传进去。
5)打印创建的对象和调用对象的没有返回值的方法和getClass方法,演示调用其他有返回值的方法报告了异常。
6)将创建动态类的实例对象的代理改成匿名内部类的形式编写,锻炼大家习惯匿名内部类。
上述实现实例对象的过程其实可以用Proxy类中的一个方法来完成:
public static Object newProxyInstance(ClassLoaderloader, Class>[] interfaces,
InvocationHandlerh) throws IllegalArgumentException返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程
eg:使用newProxyInstance方法说明
//看清楚,newProxyInstance方法,传入了三个参数。
//第二个如果有多个接口,无法用可变参数,所以用数组;
//第三个使用匿名内部类
Collectioncoll =
(Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(), //1字节码
newClass[]{Collection.class}, //2接口
newInvocationHandler(){ //3
publicObject invoke(Object proxy, Method method,
Object[]args) throws Throwable {
//TODO Auto-generated method stub
returnnull;
}
});
eg:在此基础上演示invoke中的运行
Collection coll =
(Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(),
newClass[]{Collection.class},
newInvocationHandler(){
ArrayListtarget = new ArrayList();
publicObject invoke(Object proxy, Method method,
Object[]args) throws Throwable {
//输出运行时间看看
longbeginTime = System.currentTimeMillis();
ObjectretVal = method.invoke(target, args);
for(intx=0 ; x<999999999 ; x++)
{
inttemp = x;
}
longendTime = System.currentTimeMillis();
System.out.println(method.getName()
+ " running " + (endTime-beginTime));
returnretVal;
}
});
coll.add("durex");
coll.add("jissbon");
coll.add("tiantian");
coll.add("darren");
System.out.println(coll.size());
/*输出:
addrunning 858
addrunning 844
addrunning 795
addrunning 797
sizerunning 795
4*/
说明当调用coll集合add方法的时候,都会去调用invoke方法。
让jvm创建动态类及其实例对象,需要给它提供哪些信息?三个方面:
1)生成的类中有哪些方法,通过让其实现哪些接口的方式进行告知;
2)产生的类字节码必须有个一个关联的类加载器对象;
3)生成的类中的方法的代码是怎样的,也得由我们提供。把我们的代码写在一个约定好了接口对象的方法中,把对象传给它,它调用我的方法,即相当于插入了我的代码。提供执行代码的对象就是那个InvocationHandler对象,它是在创建动态类的实例对象的构造方法时传递进去的。在上面的InvocationHandler对象的invoke方法中加一点代码,就可以看到这些代码被调用运行了。
>>让动态生成的类成为目标类的代理
怎样将目标类传进去?
1)直接在InvocationHandler实现类中创建目标类的实例对象,可以看运行效果和加入日志代码,但没有实际意义。
2)为InvocationHandler实现类注入目标类的实例对象,不能采用匿名内部类的形式了。
让匿名的InvocationHandler实现类访问外面方法中的目标类实例对象的final类型的引用变量。
3)将创建代理的过程改为一种更优雅的方式,eclipse重构出一个getProxy方法绑定接收目标同时返回代理对象,让调用者更懒惰,更方便,调用者甚至不用接触任何代理的API。
将系统功能代码模块化,即将切面代码也改为通过参数形式提供,怎样把要执行的系统功能代码以参数形式提供?
1)把要执行的代码装到一个对象的某个方法里,然后把这个对象作为参数传递,接收者只要调用这个对象的方法,即等于执行了外界提供的代码!
2)为bind方法增加一个Advice参数。
eg:抽出目标对形象和invoke中的执行代码
//————————main,抽出了目标————————
…………………………………………
ArrayList target = new ArrayList();
//利用方法给出目标和执行代码(MyAdvice)并返回代理
Collectioncoll = (Collection) getProxy(target, new MyAdvice());
coll.add("durex");
System.out.println(coll.size());
}
//代理生成方法
private static Object getProxy(finalArrayList target, final Advice advice) {
Objectcoll = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
newInvocationHandler(){
publicObject invoke(Object proxy, Method method,
Object[]args) throws Throwable {
//输出运行时间看看
advice.beforeMethod(method);
ObjectretVal = method.invoke(target, args);
advice.afterMethod(method);
returnretVal;
}
});
returncoll;
}
…………………………………………
//————————interface————————
package com.proxy;
import java.lang.reflect.Method;
public interface Advice {
//一般来说有四个方法
/*1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中*/
//这里为演示简化,就两个方法吧,方法的参数可以自己定义
voidbeforeMethod(Method method);
voidafterMethod(Method method);
}
//————————实现类,相当于抽取代码————————
package com.proxy;
import java.lang.reflect.Method;
public class MyAdvice implements Advice {
longbeginTime = 0;
publicvoid afterMethod(Method method) {
System.out.println("end");
for(intx=0 ; x<999999999 ; x++)
{
inttemp = x;
}
longendTime = System.currentTimeMillis();
System.out.println(method.getName()
+" running "
+(endTime-beginTime));
}
publicvoid beforeMethod(Method method) {
System.out.println("begin");
beginTime= System.currentTimeMillis();
}
}
>>实现AOP功能的封装与配置
工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。其getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象的getProxy方法返回的对象。
eg:模拟spring的可配置的AOP框架
//———————— BeanFactory ————————
package com.cty.aopFramework;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class BeanFactory {
Propertiesprops = new Properties();
BeanFactory(InputStreamips)
{
try{
props.load(ips);
}catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
publicObject getBean(String beanName)
{
Objectobject = null;
try{
StringclassName = props.getProperty(beanName);
Classclazz = Class.forName(className);
object= clazz.newInstance();
if(objectinstanceof ProxyFactoryBean)
{
ProxyFactoryBeanproxyFactoryBean = (ProxyFactoryBean) object;
StringtargetName = props.getProperty(beanName + ".target");
StringadviceName = props.getProperty(beanName + ".advice");
proxyFactoryBean.setAdvice((Advice)Class.
forName(adviceName).newInstance());
proxyFactoryBean.
setTarget(Class.forName(targetName).newInstance());
object= proxyFactoryBean.getProxy();
}
}catch (Exception e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
returnobject;
}
}
//————————ProxyFactoryBean ————————
package com.cty.aopFramework;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactoryBean {
privateObject target;
privateAdvice advice;
publicObject getProxy() {
Objectproxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
newInvocationHandler(){
@Override
publicObject invoke(Object obj, Method method, Object[] args)
throwsThrowable {
//TODO Auto-generated method stub
advice.beforeMethod(method);
ObjectretVal = method.invoke(target, args);
advice.afterMethod(method);
returnretVal;
}
});
returnproxy;
}
publicObject getTarget() {
returntarget;
}
publicvoid setTarget(Object target) {
this.target= target;
}
publicAdvice getAdvice() {
returnadvice;
}
publicvoid setAdvice(Advice advice) {
this.advice= advice;
}
}
//———————— interfaceadvice ————————
package com.cty.aopFramework;
import java.lang.reflect.Method;
public interface Advice {
//一般来说有四个方法
/*1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中*/
//这里为演示简化,就两个方法吧,方法的参数可以自己定义
voidbeforeMethod(Method method);
voidafterMethod(Method method);
}
//———————— implementsmyadvice ————————
package com.cty.aopFramework;
import java.lang.reflect.Method;
public class MyAdvice implements Advice {
longbeginTime = 0;
publicvoid afterMethod(Method method) {
System.out.println("end");
for(intx=0 ; x<999999999 ; x++)
{
inttemp = x;
}
longendTime = System.currentTimeMillis();
System.out.println(method.getName()
+" running "
+(endTime-beginTime));
}
publicvoid beforeMethod(Method method) {
System.out.println("begin");
beginTime= System.currentTimeMillis();
}
}
//———————— config.properties————————
ArrayList=java.util.ArrayList
ProxyFactoryBean=com.cty.aopFramework.ProxyFactoryBean
ProxyFactoryBean.advice=com.cty.aopFramework.MyAdvice
ProxyFactoryBean.target=java.util.ArrayList
//———————— main ————————
package com.cty.aopFramework;
import java.io.InputStream;
import java.util.ArrayList;
public class AopFrameworkTest {
publicstatic void main(String[] args) {
InputStreamips =AopFrameworkTest.class.getResourceAsStream("config.properties");
BeanFactorybeanFactory = new BeanFactory(ips);
//ArrayListbean = (ArrayList)beanFactory.getBean("ArrayList");
//bean.add("abc");
Objectbean = beanFactory.getBean("ProxyFactoryBean");
System.out.println(bean.getClass().getName());
}
}