|
java动态代理原理及解析 |
|
|
java动态代理原理及解析
代理:设计模式
代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个真实对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
通过代理层这一中间层,有效的控制对于真实委托类对象的直接访问,同时可以实现自定义的控制策略(Spring的AOP机制),设计上获得更大的灵活性。
java动态代理的类和接口(jdk1.6源码)
1,java.lang.reflect.Proxy:动态代理机制的主类,提供一组静态方法为一组接口动态的生成对象和代理类。
//方法1:该方法用于获取指定代理对象所关联的调用处理器
publicstaticInvocationHandlergetInvocationHandler(Objectproxy)
//方法2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
publicstaticClass>getProxyClass(ClassLoaderloader,
Class>...interfaces)
//方法3:该方法用于判断指定类对象是否是一个动态代理类
publicstaticbooleanisProxyClass(Class>cl)
//方法4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
publicstaticObjectnewProxyInstance(ClassLoaderloader,
Class>[]interfaces,InvocationHandlerh)
2,java.lang.reflect.InvocationHandler:调用处理器接口,自定义invokle方法,用于实现对于真正委托类的代理访问。
/
该方法负责集中处理动态代理类上的所有方法调用。
第一个参数既是代理类实例,
第二个参数是被调用的方法对象
第三个方法是调用参数。
调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
/
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
throwsThrowable;
3,java.lang.ClassLoader:类装载器类,将类的字节码装载到Java虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy类与普通类的唯一区别就是其字节码是由JVM在运行时动态生成的而非预存在于任何一个.class文件中。
每次生成动态代理类对象时都需要指定一个类装载器对象:newProxyInstance()方法第一个参数
动态代理机制
java动态代理创建对象的过程为如下步骤:
1,通过实现InvocationHandler接口创建自己的调用处理器;
//InvocationHandlerImpl实现了InvocationHandler接口,并能实现方法调用从代理类到委托类的分派转发
//其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
InvocationHandlerhandler=newInvocationHandlerImpl(..);
1
2
3
2,通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理类;
//通过Proxy为包括Interface接口在内的一组接口动态创建代理类的类对象
Classclazz=Proxy.getProxyClass(classLoader,newClass[]{Interface.class,...});
1
2
3,通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
//通过反射从生成的类对象获得构造函数对象
Constructorconstructor=clazz.getConstructor(newClass[]{InvocationHandler.class});
1
2
4,通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
//通过构造函数对象创建动态代理类实例
InterfaceProxy=(Interface)constructor.newInstance(newObject[]{handler});
1
2
为了简化对象创建过程,Proxy类中的newProxyInstance方法封装了2~4,只需两步即可完成代理对象的创建。
//InvocationHandlerImpl实现了InvocationHandler接口,并能实现方法调用从代理类到委托类的分派转发
InvocationHandlerhandler=newInvocationHandlerImpl(..);
//通过Proxy直接创建动态代理类实例
Interfaceproxy=(Interface)Proxy.newProxyInstance(classLoader,
newClass[]{Interface.class},
handler);
动态代理的注意点:
1,包:代理接口是public,则代理类被定义在顶层包(package为空),否则(default),代理类被定义在该接口所在包,
2,生成的代理类为publicfinal,不能被继承,
3,类名:格式是“$ProxyN”,N是逐一递增的数字,代表Proxy被第N次动态生成的代理类,要注意,对于同一组接口(接口的排列顺序也相同),不会重复创建动态代理类,而是返回一个先前已经创建并缓存了的代理类对象。提高了效率。
4,类继承关系:
Proxy类是它的父类,这个规则适用于所有由Proxy创建的动态代理类。(也算是java动态代理的一处缺陷,java不支持多继承,所以无法实现对class的动态代理,只能对于Interface的代理)而且该类还实现了其所代理的一组接口,这就是为什么它能够被安全地类型转换到其所代理的某接口的根本原因。
5,代理类的根类java.lang.Object中有三个方法也同样会被分派到调用处理器的invoke方法执行,它们是hashCode,equals和toString,
代码在反编译中
一个动态代理的demo
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
importjava.lang.reflect.Proxy;
publicclassHelloServiceProxyimplementsInvocationHandler{
privateObjecttarget;
/
绑定委托对象并返回一个【代理占位】
@paramtarget真实对象
@return代理对象【占位】
/
publicObjectbind(Objecttarget,Class[]interfaces){
this.target=target;
//取得代理对象
returnProxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClawww.shanxiwang.netss().getInterfaces(),this);
}
@Override
/
同过代理对象调用方法首先进入这个方法.
@paramproxy--代理对象
@parammethod--方法,被调用方法.
@paramargs--方法的参数
/
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{
System.err.println("############我是JDK动态代理################");
Objectresult=null;
//反射方法前调用
System.err.println("我准备说hello。");
//反射执行方法相当于调用target.sayHelllo;
result=method.invoke(target,args);
//反射方法后调用.
System.err.println("我说过hello了");
returnresult;
}
}
其中,bind方法中的newProxyInstanc方法,就是生成一个代理对象,第一个参数是类加载器,第二个参数是真实委托对象所实现的的接口(代理对象挂在那个接口下),第三个参数this代表当前HelloServiceProxy类,换句话说是使用HelloServiceProxy作为对象的代理。
invoke方法有三个参数:第一个proxy是代理对象,第二个是当前调用那个方法,第三个是方法的参数。
publicclassProxyTest{
publicstaticvoidmain(String[]args){
HelloServiceProxyproxy=newHelloServiceProxy();
HelloServiceservice=newHelloServiceImpl();
//绑定代理对象。
service=(HelloService)proxy.bind(service,newClass[]{HelloService.class});
//这里service经过绑定,就会进入invoke方法里面了。
service.sayHello("张三");
}
}
测试结果:
############我是JDK动态代理################
我准备说hello。
hello张三
我说过hello了
1
2
3
4
源码跟踪
Proxy类
//映射表:用于维护类装载器对象到其对应的代理类缓存
privatestaticMaploaderToCache=newWeakHashMap();
//标记:用于标记一个动态代理类正在被创建中
privatestaticObjectpendingGenerationMarker=newObject();
//同步表:记录已经被创建的动态代理类类型,主要被方法isProxyClass进行相关的判断
privatestaticMapproxyClasses=Collections.synchronizedMap(newWeakHashMap());
//关联的调用处理器引用
protectedInvocationHandlerh;
Proxy静态方法newProxyInstance
publicstaticObjectnewProxyInstance(ClassLoaderloader,
Class>[]interfaces,
InvocationHandlerh)
throwsIllegalArgumentException{
//检查h不为空,否则抛异常
if(h==null){
thrownewNullPointerException();
}
//获得与制定类装载器和一组接口相关的代理类类型对象
/
Lookuporgeneratethedesignatedproxyclass.
/
Class>cl=getProxyClass0(loader,interfaces);
//通过反射获取构造函数对象并生成代理类实例
/
Invokeitsconstructorwiththedesignatedinvocationhandler.
/
try{
finalConstructor>cons=cl.getConstructor(constructorParams);
finalInvocationHandlerih=h;
SecurityManagersm=System.getSecurityManager();
if(sm!=null&&ProxyAcctessHelper.needsNewInstanceCheck(cl)){
//createproxyinstancewithdoPrivilegeastheproxyclassmay
//implementnon-publicinterfacesthatrequiresaspecialpermission
returnAccessController.doPrivileged(newPrivilegedAction |
|
|
|
|
|
|
|
|
|
|