zoukankan      html  css  js  c++  java
  • 代理模式

    代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。

    换句话说,使用代理对象,是为了在不修改目标对象的基础上,增强主业务逻辑。 客户类真正的想要访问的对象是目标对象,但客户类真正可以访问的对象是代理对象。客户类对目标对象的访问是通过访问代理对象来实现的。当然,代理类与目标类要实现同一个接口

    对于代理模式,需要注意以下几点:   
      (1)代理类和目标类要实现同一个接口,即业务接口。 

      (2)客户类对目标类的调用均是通过代理类完成的。

      (3)代理类的执行既执行了对目标类的增强业务逻辑,又调用了目标类的主业务逻辑。

    根据代理关系建立的时间不同,可以将代理分为两类:静态代理与动态代理。

    静态代理:

      静态代理是指,代理类在程序运行前就已经定义好,其与目标类的关系在程序运行前就已经确立

    1 package com.tongji.csis.qjj;
    2 
    3 //业务接口
    4 public interface ISomeService {
    5     String doSome();
    6     String doSecond();
    7 }
     1 package com.tongji.csis.qjj;
     2 
     3 //目标类,主要实现了业务接口的主业务逻辑,这些方法称为目标方法
     4 public class SomeServiceImpl implements ISomeService {
     5 
     6     @Override
     7     public String doSome() {
     8         System.out.println("执行doSome()");
     9         return "I Love you";
    10     }
    11 
    12     @Override
    13     public String doSecond() {
    14         System.out.println("执行doSecond()");
    15         return "China";
    16     }
    17     
    18 }
     1 package com.tongji.csis.qjj;
     2 
     3 //静态代理类
     4 //要求静态代理类与目标类实现相同的业务接口
     5 public class SomeServiceProxy implements ISomeService {
     6     //声明业务接口对象
     7     private ISomeService target;
     8     
     9     public SomeServiceProxy() {
    10         super();
    11     }
    12     //业务接口对象作为构造器参数,用于接收目标对象
    13     public SomeServiceProxy(ISomeService target) {
    14         super();
    15         this.target = target;
    16     }
    17 
    18     @Override
    19     public String doSome() {
    20         return target.doSome();
    21     }
    22     //代理方法,实现对目标方法的功能增强
    23     @Override
    24     public String doSecond() {
    25         return target.doSecond().toUpperCase();
    26     }
    27     
    28 }
     1 package com.tongji.csis.qjj;
     2 
     3 public class MyTest {
     4 
     5     public static void main(String[] args) {
     6         //定义目标对象
     7         ISomeService target = new SomeServiceImpl();
     8         //定义目标对象的代理对象
     9         ISomeService serviceProxy = new SomeServiceProxy(target);
    10         String result1 = serviceProxy.doSome();
    11         String result2 = serviceProxy.doSecond();
    12         System.out.println(result1 + "," + result2);
    13     }
    14     
    15 }

    JDK动态代理:

      动态代理是指,程序在整个运行过程中根本就不存在目标类的代理类目标对象的代理对象只是由代理生成工具(如代理工厂类)在程序运行时由JVM根据反射等机制动态生成的代理对象与目标对象的代理关系在程序运行时才确立
      对比静态代理,静态代理是指在程序运行前就已经定义好了目标类的代理类。代理类与目标类的代理关系在程序运行之前就确立了。

      动态代理的实现方式常用的有两种:使用JDK的Proxy,与通过CGLIB生成代理。 通过JDK的java.lang.reflect.Proxy类实现动态代理,会使用其静态方法newProxyInstance()依据目标对象、业务接口及业务增强逻辑三者自动生成一个动态代理对象

      JDK动态代理代码中的业务接口代码和目标类代码和上面相同;

     1 package com.tongji.csis.qjj;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 
     6 //主业务增强逻辑类
     7 public class MyExtension implements InvocationHandler {
     8 
     9     private Object target;
    10     
    11     public MyExtension(Object target) {
    12         super();
    13         this.target = target;
    14     }
    15 
    16     //增强方法,proxy:代理对象;method:目标方法;args:目标方法的参数列表
    17     @Override
    18     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    19         String result = (String) method.invoke(target,args);
    20         if ("doSecond".equals(method.getName())) {
    21             result = result.toUpperCase();
    22         }
    23         return result;
    24     }
    25 
    26 }
     1 package com.tongji.csis.qjj;
     2 
     3 import java.lang.reflect.Proxy;
     4 
     5 public class MyTest {
     6 
     7     public static void main(String[] args) {
     8         
     9         //定义目标对象
    10         ISomeService target = new SomeServiceImpl();
    11         //定义目标对象的代理对象
    12         ISomeService serviceProxy = (ISomeService) Proxy.newProxyInstance(
    13                                         target.getClass().getClassLoader(),  //获取目标对象的类加载器
    14                                         target.getClass().getInterfaces(),   //获取目标对象的所有接口
    15                                         new MyExtension(target));            //增强业务逻辑
    16         
    17         String result1 = serviceProxy.doSome();
    18         String result2 = serviceProxy.doSecond();
    19         System.out.println(result1 + "," + result2);
    20     }
    21 
    22 }

        JDK的动态代理,底层是通过“工厂+反射机制”,动态创建静态代理中的代理类。

      

      CGLIB动态代理:

        使用JDK的Proxy实现代理,要求目标类与代理类实现相同的接口。若目标类不存在接口,则无法使用该方式实现。 
        但对于无接口的类,要为其创建动态代理,就要使用CGLIB来实现CGLIB代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。所以,使用CGLIB生成动态代理,要求目标类必须能够被继承,即不能是final的类

        CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM(Java字节码操控框架),来转换字节码并生成新的类。CGLIB是通过对字节码进行增强来生成代理的。

        CGIB动态代理代码中没有业务接口代码;

     1 package com.tongji.csis.qjj;
     2 
     3 //目标类
     4 public class SomeService {
     5 
     6     public String doSome() {
     7         System.out.println("执行doSome()");
     8         return "I Love you";
     9     }
    10 
    11     public String doSecond() {
    12         System.out.println("执行doSecond()");
    13         return "China";
    14     }
    15     
    16 }
     1 package com.tongji.csis.qjj;
     2 
     3 import java.lang.reflect.Method;
     4 
     5 import net.sf.cglib.proxy.Enhancer;
     6 import net.sf.cglib.proxy.MethodInterceptor;
     7 import net.sf.cglib.proxy.MethodProxy;
     8 
     9 //CGLIB代理类的生成工厂
    10 public class CglibProxyFactory implements MethodInterceptor {
    11     
    12     private SomeService target;
    13     
    14     public CglibProxyFactory() {
    15         super();
    16     }
    17     
    18     public CglibProxyFactory(SomeService target) {
    19         super();
    20         this.target = target;
    21     }
    22 
    23     //用于创建Cglib代理对象
    24     public SomeService myProxyCreator() {
    25         //增强器:指定父类,既要增强的目标类,并指定回调接口对象
    26         Enhancer enhancer = new Enhancer();
    27         enhancer.setSuperclass(SomeService.class);
    28         enhancer.setCallback(this);
    29         return (SomeService) enhancer.create();
    30     }
    31 
    32     @Override
    33     public Object intercept(Object proxy, Method method, Object[] args,
    34             MethodProxy methodProxy) throws Throwable {
    35         String result = (String) method.invoke(target,args);
    36         if ("doSecond".equals(method.getName())) {
    37             result = result.toUpperCase();
    38         }
    39         return result;
    40     }
    41 }
     1 package com.tongji.csis.qjj;
     2 
     3 public class MyTest {
     4 
     5     public static void main(String[] args) {
     6         //定义目标对象
     7         SomeService target = new SomeService();
     8         //定义目标对象的代理对象
     9         SomeService serviceProxy = new CglibProxyFactory(target).myProxyCreator();
    10         String result1 = serviceProxy.doSome();
    11         String result2 = serviceProxy.doSecond();
    12         System.out.println(result1 + "," + result2);
    13     }
    14 
    15 }
  • 相关阅读:
    路径查看linux 向内核注册总线例子
    属性应用Android Manifest之<provider>元素中文注释
    序数序列hdu 1394
    大分类分类Zen Cart大分类下直接显示产品列表插件
    虚拟化运行[OpenStack] VMWare产品介绍
    名称磁盘Linux系统监控的CPU、Mem、IO的OID
    端口服务器黑马韩前成linux从入门到精通proftpd服务器配置
    主库配置关于Dataguard Online redo log 和 Standby redo log
    尺寸品牌Jquery 仿淘宝京东多条件筛选 可自行结合ajax加载
    设置编辑(iPhone/iPad开发)设置UITextView为不可编辑状态
  • 原文地址:https://www.cnblogs.com/qjjazry/p/6363380.html
Copyright © 2011-2022 走看看