Java动态代理详解
来源:互联网 发布:mpv mac 字幕 编辑:程序博客网 时间:2024/05/22 07:49
代理是一种设计模式,JDK的代理设计模式应用有Java动态代理。
动态代理是一种思想,委托类的方法实现通过代理类来完成。代理类和委托类实现同一个接口,即让他们实现相同的方法(因为代理类是为委托类服务的,所以必须实现委托类的方法,然后再可以在委托类前后新增加一些方法)
代理设计模式有三种角色:委托类接口,委托类实现,代理类
以上模型,代码实现:
定义接口
package com.gc.impl;public interface Subject {public void action();}
package com.gc.acion;import com.gc.impl.Subject;public class RealSubject implements Subject {@Overridepublic void action() {System.out.println("RealSubject Action Method");}}
代理类实现接口,代理实现委托类的方法并且可以在前后加上一些逻辑。
package com.gc.acion;import com.gc.impl.Subject;public class SubjectProxy implements Subject{Subject subject;public SubjectProxy(Subject subject){this.subject = subject;}@Overridepublic void action() {//before逻辑System.out.println("before RealSubject Method");//实现委托类的方法subject.action();//after逻辑System.out.println("after RealSubject Method");}}
这种编程的好处在于,对于before和after方法的公共实现不必在每一个实现类里加,只需要在公共方法里加。但是还有一个缺点,因为实现的是某一个具体的接口,所以接口不同时,每一个接口都需要实现一遍,代码也是冗余的。所以在JDK的实现中用了Java动态代理机制。
JDK的Java动态代理机制:
一般是4个角色:委托类接口,委托类实现,代理类实现和调用操作者。
两个重要的类和接口:
代理类是Proxy(类):java.lang.reflect.Proxy
调用操作者InvocationHandle(接口):java.lang.reflect.InvocationHandle
将所有的触发(invoke)真实类实现方法的动作交给调用操作者,而非代理实现类亲自去实现。
看一下Proxy源码:
重点介绍几种方法:
1、这是Proxy的带参构造方法,绑定一个调用操作者。给内部的h赋值了一个InvocationHandler
protected Proxy(InvocationHandler arg0) {Objects.requireNonNull(arg0);this.h = arg0;}
2、ClassLoader 是类装载器,interfaces是所有真实类锁拥有的全部接口数组,返回得到一个代理类Class
public static Class<?> getProxyClass(ClassLoader arg, Class[] interfaces)throws IllegalArgumentException {Class[] arg1 = (Class[]) arg0.clone();SecurityManager arg2 = System.getSecurityManager();if (arg2 != null) {checkProxyAccess(Reflection.getCallerClass(), arg, arg1);}return getProxyClass0(arg, arg1);}
3、传入类加载器ClassLoader, 委托类所拥有的全部接口数组Class[] interface,调用操作者InvocationHandler,返回得到一个对象,一个代理类对象,相当于上文例子中的Proxy(before、service()、after)
public static Object newProxyInstance(ClassLoader arg, Class<?>[] arg0,InvocationHandler arg1) throws IllegalArgumentException {Objects.requireNonNull(arg1);Class[] arg2 = (Class[]) arg0.clone();SecurityManager arg3 = System.getSecurityManager();if (arg3 != null) {checkProxyAccess(Reflection.getCallerClass(), arg, arg2);}Class arg4 = getProxyClass0(arg, arg2);try {if (arg3 != null) {checkNewProxyPermission(Reflection.getCallerClass(), arg4);}final Constructor arg5 = arg4.getConstructor(constructorParams);if (!Modifier.isPublic(arg4.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction() {public Void run() {arg5.setAccessible(true);return null;}});}return arg5.newInstance(new Object[] { arg1 });} catch (InstantiationException | IllegalAccessException arg7) {throw new InternalError(arg7.toString(), arg7);} catch (InvocationTargetException arg8) {Throwable arg6 = arg8.getCause();if (arg6 instanceof RuntimeException) {throw (RuntimeException) arg6;} else {throw new InternalError(arg6.toString(), arg6);}} catch (NoSuchMethodException arg9) {throw new InternalError(arg9.toString(), arg9);}}
4、传入一个代理类对象,得到一个InvocationHandler调用操作者
public static InvocationHandler getInvocationHandler(Object arg)throws IllegalArgumentException {if (!isProxyClass(arg.getClass())) {throw new IllegalArgumentException("not a proxy instance");} else {Proxy arg0 = (Proxy) arg;InvocationHandler arg1 = arg0.h;if (System.getSecurityManager() != null) {Class arg2 = arg1.getClass();Class arg3 = Reflection.getCallerClass();if (ReflectUtil.needsPackageAccessCheck(arg3.getClassLoader(),arg2.getClassLoader())) {ReflectUtil.checkPackageAccess(arg2);}}return arg1;}}
动态代理类是class一种在运行时才生成的class,在生成它是必须提供一组interface给它,然后Dynamic Proxy就实现了这些interface。因为动态Proxy实现了这些接口,所以可以把Dynamic Proxy实例当成是这些interface中的任一一个来使用。
当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。因为在有了调用操作类之后,代理类本身就没有必要去亲自实现了。
看一下InvocationHandler的源码,该接口只定义有一个方法:
public interface InvocationHandler {Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable;}
在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的action(),args为该方法的参数数组。
前面说到创建Proxy实例的时候,要绑定三个参数(ClassLoader,interface数组,InvocationHandle)
就是Proxy中实现的所有真实类的接口都交给它绑定的InvacationHandle类去触发真实类的实现动作。Proxy自己只负责调用。
看一个动态代理的实例:
package com.gc.impl;public interface Subject {public void action();public void hello(String s);}
package com.gc.acion;import com.gc.impl.Subject;public class RealSubject implements Subject {@Overridepublic void action() {System.out.println("RealSubject Action Method");}@Overridepublic void hello(String s) {System.out.println("RealSubject Action Method Include Args:"+s);}}
package com.gc.acion;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import com.gc.impl.Subject;public class DynamicProxy implements InvocationHandler{//要代理的真实对象private Object subject;//用构造方法给要代理的真实对象赋值public DynamicProxy(Subject subject){this.subject = subject;}@Overridepublic Object invoke(Object object, Method method, Object[] arg2)throws Throwable {//before逻辑System.out.println("before RealSubject Method");//实现委托类subject的method方法,method方法中可能传有参数为arg2method.invoke(subject, arg2);//after逻辑System.out.println("after RealSubject Method");return null;}}
package com.gc.acion;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import com.gc.impl.Subject;public class TestDynamicProxy {public static void main(String[] args) {//创建一个真实对象Subject realsub = new RealSubject();//将真实对象绑定到Dynamic Proxy上,同时也通过构造函数给DynamicProxy中的真实对象赋值InvocationHandler handler = new DynamicProxy(realsub);//创建代理类对象Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), //InvocationHandler类加载realsub.getClass().getInterfaces(), //真实对象的类接口数组,即动态代理类实现了真实类的所有接口handler);//绑定调用操作者,把对真实类的实现方法的触发都交给InvocationHalder//代理类对象调用了真实类的实现方法,关于这些方法的触发都交给了InvocationHandler(即会实现DynamicProxy的invoke)subject.action();//对应method.invoke(subject, "");真实对象,方法subject.hello("你好");//对应method.invoke(subject, arg2);真实对象,方法和参数//总结:Proxy.newProxyInstance代理类对象负责调用,InvocationHandler调用操作者负责触发。}}
- Java动态代理详解
- java动态代理详解
- Java动态代理详解
- java动态代理详解
- 详解java动态代理
- java 动态代理详解
- Java动态代理详解
- java动态代理详解
- JAVA动态代理详解
- Java动态代理详解
- Java动态代理详解
- java动态代理详解
- Java动态代理详解
- java动态代理详解
- Java动态代理详解
- Java动态代理详解
- Java动态代理详解
- java动态代理详解
- CCF第一题--数位之和
- Spring MVC框架errors标签的使用
- Java并发编程实战 之 结构化并发应用程序
- 剑指Offer(1)______二维数组中的查找
- 基于浏览器请求的国际化实现
- Java动态代理详解
- 生成一个C++对象的成本
- CCF第一题--折点计数
- 21. Merge Two Sorted Lists(Linked List-Easy)
- 割木块
- 学习淘淘商城第七课(SSM框架整合之逆向工程)
- 关于Java面向对象基本特征的一些理解
- Linux下Tomcat的安装配置
- JavaWeb跨域访问问题