java 的三种代理模式
(一)https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247485265&idx=1&sn=0ea1fe4257cb963d24829f69bb6a32da&chksm=ebd6387ddca1b16b87f12f50b24b239bed93e0e49f243ec560e2c83156ff5ceefe0a2b2e96fc&mpshare=1&scene=1&srcid=0427wPQP4tYUBtlGH5l1JR9i&key=c44bed40495664a4adac9e43d1f05551d8a4f754cb59ce155cd03562861b122f33144ac9d8403e70841b6302eb1f140b592c78f18e0454b0ee34a2ca8276efd12dbd8e67c6c51b455a6ebd0250532b8e&ascene=0&uin=MTA2NzUxMDAyNQ%3D%3D&devicetype=iMac+MacBookAir6%2C2+OSX+OSX+10.10.5+build(14F2511)&version=11020012&lang=zh_CN&pass_ticket=zTFOqug6RXGHRQVhLFV5xM2VvZe0nSmsXV1%2Fys3HrXZVPSKfgf3TVZ7FuYVWc0LA
1. 静态代理
public class UserDaoProxy implements IUserDao { private IUserDao target; public UserDaoProxy(IUserDao target){ this.target = target; } @Override public void save() { System.out.println("开始事务static"); target.save();//执行目标对象的方法 System.out.println("提交事务static"); } }
2. 动态代理
public class ProxyFactory implements InvocationHandler { //维护一个目标对象 private Object target; public ProxyFactory(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始事务jdk"); Object returnValue = method.invoke(target, args); System.out.println("提交事务jdk"); return returnValue; } //给目标对象生成代理对象 public Object getProxyInstance(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } }
// 目标对象 IUserDao target = new UserDao(); // 给目标对象,创建代理对象 IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance(); // 执行方法 【代理对象】 proxy.save(); }
3. cglib
public class ProxyFactory implements MethodInterceptor { //维护目标对象 private Object target; public ProxyFactory(Object target) { this.target = target; } //给目标对象创建一个代理对象 public Object getProxyInstance(){ //1.工具类 Enhancer en = new Enhancer(); //2.设置父类 en.setSuperclass(target.getClass()); //3.设置回调函数 en.setCallback(this); //4.创建子类(代理对象) return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("开始事务cglib"); //执行目标对象的方法 Object returnValue = method.invoke(target, args); System.out.println("提交事务cglib"); return returnValue; } }与jdk相同,
一个被代理对象,一个invoke改写埋点,一个创建代理对象
//目标对象 UserDao target = new UserDao(); //代理对象 UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance(); //执行代理对象的方法 proxy.save();
Java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
如何强制使用CGLIB实现AOP?
(1)添加CGLIB库,SPRING_HOME/cglib/*.jar
(2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK动态代理和CGLIB字节码生成的区别?
(1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
(2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final
* 实现InvocationHandler
* 使用Proxy.newProxyInstance产生代理对象
* 被代理的对象必须要实现接口
使用JDK动态代理,目标类必须实现的某个接口,如果某个类没有实现接口则不能生成代理对象。
CGLib 必须依赖于CGLib的类库,Cglib原理是针对目标类生成一个子类,覆盖其中的所有方法,所以目标类和方法不能声明为final类型。针对接口编程的环境下推荐使用JDK的代理。从执行效率上看,Cglib动态代理效率较高。在Hibernate中的拦截器其实现考虑到不需要其他接口的条件Hibernate中的相关代理采用的是CGLib来执行。
个人总结:
jdk方式,实现InvocationHandler接口,使用Proxy,基于反射、动态编译 为实现某接口的类创建代理类
cglib方式,基于字节码,生成子类改写方法,方法不能为final
此外有一个2层jdk动态代理例子:
http://www.cnblogs.com/jiangyi-uestc/p/5755133.html
JDK的代理方式主要就是通过反射跟动态编译来实现的,主要搭配InvocationHandler和Proxy来实现,下面的例子中使用了两层代理(即代理上加了一层代理)。
二、实例
1. 公共接口
1 package com.tgb.proxy; 2 3 public interface UserMgr { 4 5 void addUser(); 6 void delUser(); 7 8 }
2. 实现类
1 package com.tgb.proxy; 2 3 public class UserMgrImpl implements UserMgr { 4 5 @Override 6 public void addUser() { 7 System.out.println("添加用户...."); 8 } 9 10 @Override 11 public void delUser() { 12 System.out.println("删除用户....."); 13 } 14 15 }
3. TransactionHandler(InvocationHandler的实现)
1 package com.tgb.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class TransactionHandler implements InvocationHandler { 7 8 private Object target; 9 10 public TransactionHandler(Object target){ 11 super(); 12 this.target = target; 13 } 14 15 @Override 16 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 17 18 System.out.println("开启事务..."); 19 20 method.invoke(target); 21 22 System.out.println("提交事务..."); 23 24 return null; 25 } 26 27 28 }
4. TimeHandler(InvocationHandler的实现)
1 package com.tgb.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.util.Calendar; 6 7 public class TimeHandler implements InvocationHandler { 8 9 private Object target; 10 11 public TimeHandler(Object target) { 12 super(); 13 this.target = target; 14 } 15 16 @Override 17 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 18 19 Calendar calendar = Calendar.getInstance(); 20 21 System.out.println("start time:" + calendar.get(Calendar.HOUR_OF_DAY)); 22 23 method.invoke(target); 24 25 System.out.println("end time:" + calendar.get(Calendar.HOUR_OF_DAY)); 26 27 return null; 28 } 29 30 }
5. 测试类
1 package com.tgb.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Proxy; 5 6 public class Client { 7 8 public static void main(String[] args) { 9 10 UserMgr userMgr = new UserMgrImpl(); 11 12 // 1.第一层代理----------通过动态代理,添加事务处理 13 InvocationHandler handler = new TransactionHandler(userMgr); 14 UserMgr userMgrProxy = (UserMgr) Proxy.newProxyInstance(userMgr.getClass().getClassLoader(), 15 userMgr.getClass().getInterfaces(), handler); 16 17 // 2.第二层代理----------通过动态代理,添加时间处理 18 InvocationHandler handler2 = new TimeHandler(userMgrProxy); 19 UserMgr userMgrProxy2 = (UserMgr) Proxy.newProxyInstance(userMgrProxy.getClass().getClassLoader(), 20 userMgrProxy.getClass().getInterfaces(), handler2); 21 22 userMgrProxy2.addUser(); 23 24 System.out.println("========================================"); 25 26 userMgrProxy2.delUser(); 27 28 } 29 }
输出结果:
start time:Tue Aug 09 23:54:54 CST 2016 开启事务... 添加用户.... 提交事务... end time:Tue Aug 09 23:54:54 CST 2016 ======================================== start time:Tue Aug 09 23:54:54 CST 2016 开启事务... 删除用户..... 提交事务... end time:Tue Aug 09 23:54:54 CST 2016