7种结构型模式之:代理模式 、JDK动态代理、cglib动态代理

来源:互联网 发布:调用接口获取json数据 编辑:程序博客网 时间:2024/04/25 11:59


其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。先来看看关系图:

根据上文的阐述,代理模式就比较容易的理解了,我们看下代码:

[java] view plain copy
  1. public interface Sourceable {  
  2.     public void method();  
  3. }  

[java] view plain copy
  1. public class Source implements Sourceable {  
  2.   
  3.     @Override  
  4.     public void method() {  
  5.         System.out.println("the original method!");  
  6.     }  
  7. }  

[java] view plain copy
  1. public class Proxy implements Sourceable {  
  2.   
  3.     private Source source;  
  4.     public Proxy(){  
  5.         super();  
  6.         this.source = new Source();  
  7.     }  
  8.     @Override  
  9.     public void method() {  
  10.         before();  
  11.         source.method();  
  12.         atfer();  
  13.     }  
  14.     private void atfer() {  
  15.         System.out.println("after proxy!");  
  16.     }  
  17.     private void before() {  
  18.         System.out.println("before proxy!");  
  19.     }  
  20. }



测试类:

[java] view plain copy
  1. public class ProxyTest {  
  2.   
  3.     public static void main(String[] args) {  
  4.         Sourceable source = new Proxy();  
  5.         source.method();  
  6.     }  
  7.   
  8. }  

输出:

before proxy!
the original method!
after proxy!

代理模式的应用场景:

如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:

1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。

2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。

使用代理模式,可以将功能划分的更加清晰,有助于后期维护!


--------------------------------------------------------------------------------------------------------------------------------------------------------

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.      * 执行目标对象的方法  
  23.      */  
  24.     public Object invoke(Object proxy, Method method, Object[] args)  
  25.             throws Throwable {  
  26.           
  27.          //在目标方法执行前简单打印一下  
  28.          System.out.println("----------before----------");  
  29.            
  30.          //执行目标方法对象  
  31.          Object result=method.invoke(target, args);  
  32.            
  33.          //在目标方法执行之后简单打印一下  
  34.          System.out.println("----------after----------");  
  35.           
  36.          return result;  
  37.     }  
  38.       
  39.       
  40.     /** 
  41.      * 获取目标对象的代理对象 
  42.      * @return 代理对象 
  43.      this.target.getClass().getInterfaces()//获取被代理对象实现的所有接口
  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. }    

总结

    CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
1 0