静态代理与动态代理(JDK代理/cglib代理)的区别
前提知识:
静态代理与动态代理的区别:
静态代理:创建代理类java文件或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态代理:在程序运行时运用反射机制动态创建代理对象而成.在程序运行前代理类的.class文件不存在。
静态代理图解与代码说明: 本质是对于 (暂未发布)java装饰设计模式的一种应用。
动态代理主要包括两种模式JDK代理模式与cglib代理模式(参考spring的org.springframework.cglib.proxy包)
JDK代理主要是通过java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)函数基于(暂未发布)ClassLoader类加载机制实现,类似(暂未发布)java装饰设计模式来创建代理类
jdk代码说明:
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 5 import cn.it.TxManager; 6 7 /**创始一个使用jdk的proxy完成动态代理工具 8 * implements InvocationHandler 自己创建的一个回调的处理器 9 * */ 10 public class JDKProxyFactory implements InvocationHandler { 11 /**用于接收真实主题角色(目标对象) 多态的调用 */ 12 private Object target; 13 14 /**用于接收事务对象*/ 15 private TxManager txManager; 16 17 /**使用构造方法传递目标对象与事务对象*/ 18 public JDKProxyFactory(Object target,TxManager txManager) { 19 this.target = target; 20 this.txManager = txManager; 21 } 22 /**创建代理对象*/ 23 public Object createProxy() { 24 /** 使用java.lang.reflect.Proxy完成代理对象创建 25 * Proxy的static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) ClassLoader 类加载器 26 * 所有Class都可以拿到ClassLoader(只要拿到它就可以了) 用于加载 class类文件 27 interfaces 得到目标对象的实现接口的Class[] 28 抽象主题角色 ,要从真实主题角色中拿到 29 java.lang.reflect.InvocationHandler 代理执行程序接口 30 主要是让咱们来完成相应的处理(添加上咱们想要在代理方法加添加的代码) 31 由于JDKProxyFactory本类implements实现InvocationHandler接口 32 InvocationHandler h 参数就是this对象 33 */ 34 return Proxy.newProxyInstance( 35 this.getClass().getClassLoader(), 36 target.getClass().getInterfaces(), //真实主题角色的接口 37 this 38 ); 39 } 40 41 /** 42 * 通过反射执行回调方法 在代理实例上处理方法调用并返回结果。 43 * Object proxy : 代理对象(几乎不用) 44 * java.lang.reflect.Method method : 实际执行的方法对象 45 * Object[] args : 实际调用方法中的参数 46 * 返回的是方法执行之后的返回值 47 */ 48 @Override 49 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 50 51 Object result = null; 52 try { 53 txManager.begin();//开始事务 调用事务对象的方法 54 /** 55 java.lang.reflect.Method method 的 Object invoke(Object obj, Object... args) 56 相当于result=target.invoke(args)*/ 57 58 /** 加强 target.getName() 能获得执行的对象的类名 能够针对某些类来进行增强 59 if(target.getName().endwith("Dao")){ 60 //增强的代码 61 } 62 */ 63 64 /**对执行的方法进行判断 针对某些方法对象增强 65 save可以通过配置文件读取 dog4j解析 66 如 startwith endwith equals 来进行判断 67 */ 68 if(method.endwith("save")){ 69 //增强save方法执行前的代码 70 result = method.invoke(target, args); 71 //增强save方法执行后的代码 72 }else{ 73 result = method.invoke(target, args); 74 } 75 76 txManager.commit();//提交事务 77 } catch (Exception e) { 78 txManager.rollback();//回滚事务 79 e.printStackTrace(); 80 } 81 return result; 82 } 83 } 84 85 @Test 86 public void testProxy() throws Exception { 87 User user = new User("小红"); 88 IUserService userService = new UserServiceImpl(); 89 TxManager txManager = new TxManager(); 90 91 JDKProxyFactory handler = new JDKProxyFactory(userService,txManager); 92 IUserService proxy = (IUserService)handler.createProxy(); 93 // JDK底层使用的是装饰设计模式的代理 94 //UserServiceImpl proxy = (UserServiceImpl)handler.createProxy();会报错 CGlib不会报错 95 96 //proxy.update(); 97 proxy.save(user); 98 }
cglib代理模式主要是通过org.springframework.cglib.proxy包利用spring的jar包中内置的asm字节码操作框架子包,利用(暂未发布)java继承增强的原理生成代理类
Cglib代理模式代码案例说明
import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; /***cglib创建的 动态代理工具 */ public class CglibProxyFactory implements MethodInterceptor { private Object target; private TxManager txManager; public CglibProxyFactory(Object target,TxManager txManager) { this.target = target; this.txManager = txManager; } // 创建代理对象 public Object createProxy() { // 1.创建Enhancer Enhancer enhance = new Enhancer(); // 2.参数:传递目标对象的Class 这样enhance对象就是目标对象的子类 底层使用子类继承的方式来增强父类方法 enhance.setSuperclass(target.getClass()); // 3.设置回调操作 (相当于InvocationHandler) //传入Callback callback CglibProxyFactory implements MethodInterceptor implements Callback //所以 this也就是callback对象 enhance.setCallback(this); return enhance.create(); } /** * 回调方法 参考 InvocationHandler中的invoke方法内的写法 * Object proxy : 代理对象(几乎不用) * Method method : 执行的方法 * Object[] args : 方法中的参数 * MethodProxy mehtodProxy : 代理方法(用不到) 子类复写的方法 * 返回的是方法执行之后的返回值 */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methdoProxy) throws Throwable { System.out.println("日志操作...."); return method.invoke(target, args); // 与jdk的proxy中操作类似 // return methdoProxy.invokeSuper(proxy, args); 不推荐 } } @Test public void testProxy() throws Exception { User user = new User("小红"); //真实主题角色 UserServiceImpl userService = new UserServiceImpl(); TxManager txManager = new TxManager(); //代理主题主题没创建出来 CglibProxyFactory handler = new CglibProxyFactory(userService, txManager); UserService obj = (UserService)handler.createProxy(); UserServiceImpl obj = (UserServiceImpl)handler.createProxy(); // UserServiceImpl$$EnhancerByCGLIB$$2536a285 System.out.println(obj.getClass()); obj.save(user); }
更多详情:请参考我的GitHub