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
原文地址:https://www.cnblogs.com/lyh421/p/6795898.html