2017.5.1 java动态代理总结
参考来自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
1.代理模式
1 代理类和委托类有相同接口。 2 代理类负责为委托类:预处理消息 3 过滤消息 4 把消息转发给委托类 5 事后处理消息等 6 代理类和委托类会相关联。 7 代理类不真正实现服务,而是通过调用委托类的相关方法,来提供服务。
2.代理的分类
1 静态代理:由程序员创建,或者由特定工具自动生成源代码,再对其编译。在运行之前,代理类的.class文件就存在了。 2 动态代理:在程序运行时,根据java的反射机制动态创建。
3 jdk动态代理:委托类必须实现接口。
4 Cglib动态代理:委托类不用实现接口,针对类。
2.1 静态代理
(1)实例
1 public interface Count { 2 // 查看账户方法 3 public void queryCount(); 5 // 修改账户方法 6 public void updateCount(); 8 }
1 public class CountImpl implements Count { 2 3 @Override 4 public void queryCount() { 5 System.out.println("查看账户方法..."); 6 } 7 8 @Override 9 public void updateCount() { 10 System.out.println("修改账户方法..."); 12 } 13 }
创建一个代理类,可以看到CountProxy和CountImpl实现了同样的接口:Count。
1 public class CountProxy implements Count { 2 private CountImpl countImpl; 3 4 /** 5 * 覆盖默认构造器 6 * 7 * @param countImpl 8 */ 9 public CountProxy(CountImpl countImpl) { 10 this.countImpl = countImpl; 11 } 12 13 @Override 14 public void queryCount() { 15 System.out.println("事务处理之前"); 16 // 调用委托类的方法; 17 countImpl.queryCount(); 18 System.out.println("事务处理之后"); 19 } 20 21 @Override 22 public void updateCount() { 23 System.out.println("事务处理之前"); 24 // 调用委托类的方法; 25 countImpl.updateCount(); 26 System.out.println("事务处理之后"); 27 } 28 29 }
(2)测试
由测试可知,采用constructor关联起来的proxy和impl,必须是1对1的,十分低效。
1 public class TestCount { 2 public static void main(String[] args) { 3 CountImpl countImpl = new CountImpl(); 4 CountProxy countProxy = new CountProxy(countImpl); 5 countProxy.updateCount(); 6 countProxy.queryCount(); 7 } 8 }
显然,通过上面的代码可以知道,这样的代理类只能为一个接口服务,会产生过多的代理类。而且所有的代理类中除了调用的方法不一样,其他操作都一样,重复代码过多。为了使用一个代理类来完成全部的代理功能,显然不能在运行前就生成好代理类的.class文件。即,必须使用动态代理。
2.2 JDK动态代理
(1)interface InvocationHandler
1 public interface InvocationHandler { 2 public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 3 }
参数说明:
1 Object proxy:指被代理的对象。 2 Method method:要调用的方法 3 Object[] args:方法调用时所需要的参数
(2)class Proxy
java.lang.reflect.Proxy类提供了一个方法:newProxyInstance。
1 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
参数说明:
1 ClassLoader loader:类加载器 2 Class<?>[] interfaces:得到全部的接口 3 InvocationHandler h:得到InvocationHandler接口的子类实例
(3)实例
1 public interface BookFacade { 2 public void addBook(); 3 } 4 5 public class BookFacadeImpl implements BookFacade { 6 7 @Override 8 public void addBook() { 9 System.out.println("增加图书方法。。。"); 10 } 11 }
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 5 public class BookFacadeProxy implements InvocationHandler { 6 private Object target; 7 /** 8 * 绑定委托对象并返回一个代理类 9 * @param target 委托对象 10 * @return 代理类 11 */ 12 public Object bind(Object target) { 13 this.target = target; 14 //取得代理对象 //要绑定接口(这是一个缺陷,cglib弥补了) 15 return Proxy.newProxyInstance(target.getClass().getClassLoader(),
16 target.getClass().getInterfaces(),
17 this); 17 } 18 19 @Override 20 /** 21 * 调用委托类的方法 22 */ 23 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 25 Object result=null; 26 System.out.println("事物开始"); 27 //执行方法 28 result=method.invoke(target, args); 29 System.out.println("事物结束"); 30 return result; 31 } 32 }
(4)测试
由测试可知,此时只需要一个代理类,就可以通用了。但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
1 public class TestProxy { 2 3 public static void main(String[] args) { 4 BookFacadeProxy proxy = new BookFacadeProxy(); 5 BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl()); 6 bookProxy.addBook(); 7 } 9 }
2.3 Cglib动态代理
由前面可知,当委托类并没有实现某个接口(implements someInterface)时,jdk动态代理就不能使用了。
cglib是针对类来实现代理(没有实现某个接口也不会造成影响),原理:对委托类生成一个子类(局限:final),并覆盖其中方法实现增强。
(1)实例
1 public class BookFacadeImpl1 { //没有implements BookFacade 2 public void addBook() { 3 System.out.println("增加图书的普通方法..."); 4 } 5 }
1 import java.lang.reflect.Method; 2 3 import net.sf.cglib.proxy.Enhancer; 4 import net.sf.cglib.proxy.MethodInterceptor; 5 import net.sf.cglib.proxy.MethodProxy; 6 7 public class BookFacadeCglib implements MethodInterceptor { 8 private Object target; 9 10 /** 11 * 创建代理对象 13 * @param target 委托类 14 * @return 代理类 15 */ 16 public Object getInstance(Object target) { 17 this.target = target; 18 Enhancer enhancer = new Enhancer(); 19 enhancer.setSuperclass(this.target.getClass()); 20 // 回调方法 21 enhancer.setCallback(this); 22 // 创建代理对象 23 return enhancer.create(); 24 } 25 26 @Override 27 // 回调方法 28 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 30 System.out.println("事物开始"); 31 proxy.invokeSuper(obj, args); 32 System.out.println("事物结束"); 33 return null; 34 } 35 }
(2)测试
1 public class TestCglib { 2 3 public static void main(String[] args) { 4 BookFacadeCglib cglib=new BookFacadeCglib(); 5 BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); 6 bookCglib.addBook(); 7 } 8 }
3.总结
1 静态代理缺点:代码一对一,重复冗余,编译时就需要存在代理类的.class文件。 2 动态代理优点:动态生成,统一处理,运行时生成代理类。 3 jdk动态代理: Proxy,InvocationHandler 4 cglib动态代理:MethodInterceptor
fighting for this