java动静态代理与cglib代理

说到代理,脑袋中浮现一大堆代理相关的名词,代理模式,静态代理,jdk代理,cglib代理等等。

记忆特别深刻的是,一次面试中,一位面试官问我,spring的AOP核心采用的设计模式是什么什么模式,阅读过24种设计模式,以及阅读过spring源代码的我竟然答错了,回想起来,真是日了狗了,学过那么多遍的东西都忘记了,结果是装逼失败,自己要狠下心来,把代理都搞懂!


代理模式简述

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 


静态代理

由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。下面通过例子展示。

定义接口

[java]  view plain  copy
  1. /**  
  2.  * 定义一个账户接口  
  3.  *   
  4.  * @author Fighter 
  5.  * @date 2016-04-20 
  6.  *   
  7.  */    
  8. public interface Count {    
  9.     // 查看账户方法    
  10.     public void queryCount();    
  11.     
  12.     // 修改账户方法    
  13.     public void updateCount();    
  14.     
  15. }   

实现接口

[java]  view plain  copy
  1. /**  
  2.  * 委托类(包含业务逻辑)  
  3.  *   
  4.  * @author Fighter 
  5.  * @date 2016-04-20 
  6.  *   
  7.  */    
  8. public class CountImpl implements Count {    
  9.     
  10.     @Override    
  11.     public void queryCount() {    
  12.         System.out.println("查看账户方法...");    
  13.     
  14.     }    
  15.     
  16.     @Override    
  17.     public void updateCount() {    
  18.         System.out.println("修改账户方法...");    
  19.     
  20.     }    
  21.     
  22. }     

添加代理

[java]  view plain  copy
  1. /**  
  2.  * 这是一个代理类(增强CountImpl实现类)  
  3.  *   
  4.  * @author Fighter 
  5.  * @date 2016-04-20 
  6.  *   
  7.  */    
  8. public class CountProxy implements Count {    
  9.     private CountImpl countImpl;    
  10.     
  11.     /**  
  12.      * 覆盖默认构造器  
  13.      *   
  14.      * @param countImpl  
  15.      */    
  16.     public CountProxy(CountImpl countImpl) {    
  17.         this.countImpl = countImpl;    
  18.     }    
  19.     
  20.     @Override    
  21.     public void queryCount() {    
  22.         System.out.println("事务处理之前");    
  23.         // 调用委托类的方法;    
  24.         countImpl.queryCount();    
  25.         System.out.println("事务处理之后");    
  26.     }    
  27.     
  28.     @Override    
  29.     public void updateCount() {    
  30.         System.out.println("事务处理之前");    
  31.         // 调用委托类的方法;    
  32.         countImpl.updateCount();    
  33.         System.out.println("事务处理之后");    
  34.     
  35.     }    
  36.     
  37. }     

测试

[java]  view plain  copy
  1. /**  
  2.  *测试Count类  
  3.  *   
  4.  * @author Fighter 
  5.  * @date 2016-04-20 
  6.  *   
  7.  */    
  8. public class TestCount {    
  9.     public static void main(String[] args) {    
  10.         CountImpl countImpl = new CountImpl();    
  11.         CountProxy countProxy = new CountProxy(countImpl);    
  12.         countProxy.updateCount();    
  13.         countProxy.queryCount();    
  14.     
  15.     }    
  16. }     

JDK动态代理

特点:只能对实现了接口的类生产代理,不能针对类


定义接口

[java]  view plain  copy
  1. /** 
  2.  * 创建业务接口,包含业务可以提供对外的接口 
  3.  *  
  4.  * @author Fighter 
  5.  * @date 2016-04-19 
  6.  * 
  7.  */  
  8. public interface UserService{  
  9.       
  10.     /** 
  11.      * 目标方法  
  12.      */  
  13.     public void add();  
  14. }  

定义实现类

[java]  view plain  copy
  1. /** 
  2.  * 创建业务接口实现类 
  3.  *  
  4.  * @author Fighter 
  5.  * @date 2016-04-19 
  6.  * 
  7.  */  
  8. public class UserServiceImpl implements UserService{  
  9.     @Override  
  10.     public void add() {  
  11.      System.out.println("----------add----------");  
  12.           
  13.     }  
  14. }  

定义代理

[java]  view plain  copy
  1. /** 
  2.  * 自定义简单的Invocation,对接口提供的方法进行增强 
  3.  *  
  4.  * @author Fighter 
  5.  * @date 2016-04-19 
  6.  */  
  7. public class MyInvocationHandler implements InvocationHandler {  
  8.       
  9.       
  10.     //目标对象  
  11.     private Object target;  
  12.       
  13.     /** 
  14.      * 构造方法 
  15.      * @param target 目标对象 
  16.      */  
  17.     public MyInvocationHandler(Object target) {  
  18.         super();  
  19.         this.target=target;  
  20.     }  
  21.        
  22.     <span style="white-space:pre">    </span>/** 
  23.      * 执行目标对象的方法  
  24.      */  
  25.     public Object invoke(Object proxy, Method method, Object[] args)  
  26.             throws Throwable {  
  27.           
  28.          //在目标方法执行前简单打印一下  
  29.          System.out.println("----------before----------");  
  30.            
  31.          //执行目标方法对象  
  32.          Object result=method.invoke(target, args);  
  33.            
  34.          //在目标方法执行之后简单打印一下  
  35.          System.out.println("----------after----------");  
  36.           
  37.          return result;  
  38.     }  
  39.       
  40.       
  41.     /** 
  42.      * 获取目标对象的代理对象 
  43.      * @return 代理对象 
  44.      */  
  45.     public Object getProxy(){  
  46.         return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),   
  47.                 this.target.getClass().getInterfaces(),this);  
  48.     }  
  49.       
  50.       
  51. }  

jdk动态代理测试

[java]  view plain  copy
  1. public class ProxyTest{  
  2.       
  3.     @Test  
  4.     public void testProxy() throws Throwable{  
  5.         //实例化目标对象  
  6.         UserService userService=new UserServiceImpl();  
  7.           
  8.         //实例化Invocation  
  9.         MyInvocationHandler invocationHandler=new MyInvocationHandler(userService);  
  10.           
  11.         //根据目标生成代理对象  
  12.         UserService proxy=(UserService)invocationHandler.getProxy();  
  13.           
  14.         //调用代理对象方法  
  15.         proxy.add();  
  16.     }  
  17. }  


CGLIB动态代理示例


JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 

CGLIB是一个强大的高性能的代码生成包。被广泛的许多AOP框架使用,如Spring的AOP和dynaop,为他们提供方法的interceptor(拦截),最流行的是OR Mapping工具Hibernate也是使用CGLIB来代理单端的single-ended(多对一和一对一)关联(对集合的延迟抓取是采用其他机制实现)。EsayMock和jMock是通过模仿(moke)对象来测试java代码的包。他们都是通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。

我们先通过demo来快速了解CGLIB的使用示例。


定义实现类

[java]  view plain  copy
  1. /**  
  2.  * 这个是没有实现接口的实现类  
  3.  *   
  4.  * @author student  
  5.  *   
  6.  */    
  7. public class BookFacadeImpl {    
  8.     public void addBook() {    
  9.         System.out.println("增加图书的普通方法...");    
  10.     }    
  11. }   

定义代理

[java]  view plain  copy
  1. /**  
  2.  * 使用cglib动态代理  
  3.  *   
  4.  * @author student  
  5.  *   
  6.  */    
  7. public class BookFacadeCglib implements MethodInterceptor {    
  8.     private Object target;    
  9.     
  10.     /**  
  11.      * 创建代理对象  
  12.      *   
  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,    
  29.             MethodProxy proxy) throws Throwable {    
  30.         System.out.println("事物开始");    
  31.         proxy.invokeSuper(obj, args);    
  32.         System.out.println("事物结束");    
  33.         return null;    
  34.     
  35.     
  36.     }    
  37.     
  38. }    

编写Cglib测试

[java]  view plain  copy
  1. public class TestCglib {    
  2.         
  3.     public static void main(String[] args) {    
  4.         BookFacadeCglib cglib=new BookFacadeCglib();    
  5.         BookFacadeImpl bookCglib=(BookFacadeImpl)cglib.getInstance(new BookFacadeImpl());    
  6.         bookCglib.addBook();    
  7.     }    
  8. }    

总结

当阅读到spring的AOP章节的时候发现其中使用了代理的一些方法,在此复习一下代理的一些实现以及操作。代理-Spring AOP的核心设计模式。

猜你喜欢

转载自blog.csdn.net/pingoole/article/details/78344595