您的位置:首页 > 编程语言 > Java开发

2017.5.1 java动态代理总结

2018-01-04 16:40 232 查看
参考来自: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


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: