zoukankan      html  css  js  c++  java
  • java代理(静态代理和jdk动态代理以及cglib代理)

     

    目录(?)[+]

     

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

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

    代理模式简述

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

    静态代理

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

    定义接口

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    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
     
     在CODE上查看代码片派生到我的代码片
    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
     
     在CODE上查看代码片派生到我的代码片
    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
     
     在CODE上查看代码片派生到我的代码片
    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
     
     在CODE上查看代码片派生到我的代码片
    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
     
     在CODE上查看代码片派生到我的代码片
    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
     
     在CODE上查看代码片派生到我的代码片
    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
     
     在CODE上查看代码片派生到我的代码片
    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
     
     在CODE上查看代码片派生到我的代码片
    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
     
     在CODE上查看代码片派生到我的代码片
    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
     
     在CODE上查看代码片派生到我的代码片
    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的核心设计模式。
  • 相关阅读:
    整理打印PI值
    使用自连接、for xml path('')和stuff合并显示多行数据到一行中(转)
    ThinkPHP+jQuery EasyUI Datagrid查询数据的简单处理
    ThinkPHP学习(三)
    Apache+PHP配置PATHINFO的一个小问题
    ThinkPHP学习(二)
    接口签名工具类
    RSA加密和解密工具类
    kafka项目中踩到的一个坑(客户端和服务器端版本不一致问题)
    自己实现字符串转整数(不使用JDK的字符串转整数的方法)
  • 原文地址:https://www.cnblogs.com/jiligalaer/p/6810101.html
Copyright © 2011-2022 走看看