• 代理模式


    一、代理模式的基本介绍

    1. 代理模式:为一个对象提供一个替身,以控制对这个对象的访问,即通过代理对象访问目标对象,这样做的好处是:可以在目标对象实现的基础上增强额外的功能操作,即扩展目标对象的功能。
    2. 被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象
    3. 代理模式有不同的形式,主要有三种:静态代理、动态代理和Cglib代理

      二.静态代理:

    1. 创建ITeacherDao接口
      package com.design.design.proxy.staticproxy;
      
      /**
       * @author: GuanBin
       * @date: Created in 下午11:52 2019/7/20
       */
      public interface ITeacherDao {
          /**
           * 授课的方法
           */
          void teach();
      }
    2. TeacherDao、TeacherDaoProxy都要实现IITeacherDao接口
      package com.design.design.proxy.staticproxy;
      
      /**
       * @author: GuanBin
       * @date: Created in 下午11:56 2019/7/20
       */
      public class TeacherDao implements ITeacherDao {
          @Override
          public void teach() {
      
              System.out.println("*****老是正在授课*****");
          }
      }
      3.被代理对象传入代理类的构造方法中,在代理类中实现的teach方法中,除了执行被代理类的teach方法外,还可以执行其他的业务逻辑操作
      package com.design.design.proxy.staticproxy;
      
      /**
       * @author: GuanBin
       * @date: Created in 下午11:58 2019/7/20
       */
      public class TeacherDaoProxy implements ITeacherDao {
      
          private ITeacherDao target;
      
      
          public TeacherDaoProxy (ITeacherDao target) {
              this.target=target;
          }
      
          @Override
          public void teach() {
              System.out.println("开始代理");
              target.teach();
              System.out.println("提交代理");
      
          }
      }

      4.Client中获取代理对象,并执行被代理类的teach方法

      package com.design.design.proxy.staticproxy;
      
      /**
       * @author: GuanBin
       * @date: Created in 上午12:05 2019/7/21
       */
      public class Client {
      
          public static void main(String[] args) {
      
              //创建目标对象(被代理对象)
              TeacherDao teacherDao = new TeacherDao();
      
              //创建代理对象,同时将被代理对象传递给代理对象
              TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
      
      
              //通过代理对象,调用到被代理对象的方法
              //即:执行的是代理对象的方法,代理对象再去调用目标对象的方法
              teacherDaoProxy.teach();
      
          }
      }

       三、动态代理

    1. 代理对象不需要实现接口,但是目标对象要实现接口,否则不能用动态代理
    2. 代理对象的生成,是利用JDK的api动态的在内存中构建对象
    3. 动态代理也叫做,jdk代理,接口代理
    •       jdk中生成代理对象的api,代理类所在的包:java.lang.reflect.Proxy
    •       jdk代理只需要使用Proxy.newProxyInstance方法
    1.   创建ITeacherDao接口
      package com.design.design.proxy.dynamic;
      
      /**
       * @author: GuanBin
       * @date: Created in 下午11:52 2019/7/20
       */
      public interface ITeacherDao {
          /**
           * 授课的方法
           */
          void teach();
      }
    2. 创建TeacherDao并实现ITeacherDao接口
      package com.design.design.proxy.dynamic;
      
      
      /**
       * @author: GuanBin
       * @date: Created in 下午11:56 2019/7/20
       */
      public class TeacherDao implements ITeacherDao {
          @Override
          public void teach() {
      
              System.out.println("*****老师正在授课*****");
          }
      }
    3. 创建代理工程
      package com.design.design.proxy.dynamic;
      
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy;
      
      /**
       * @author: GuanBin
       * @date: Created in 下午12:44 2019/7/21
       */
      public class ProxyFactory {
      
      
          private Object target;
      
          public ProxyFactory(Object target) {
              this.target = target;
          }
      
          /**
           * public static Object newProxyInstance(ClassLoader loader,
           *      Class<?>[] interfaces,
           *      InvocationHandler h)
           * 1.loader,当前目标对象的类加载器,获取类加载器的方法固定
           * 2.Class<?>[] interfaces:目标对象实现的接口类型,使用泛型确认接口类型
           * 3.InvocationHandler h:事情处理,执行目标对象的方法时,会触发事情处理器方法
           *
           * @return
           */
          public Object getProxyInstance() {
              return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                      target.getClass().getInterfaces(),
                      new InvocationHandler() {
                          @Override
                          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                              System.out.println("jdk代理开始");
                              //通过反射机制调用目标对象的方法
                              Object returnVal = method.invoke(target, args);
                              System.out.println("jdk代理提交");
                              return returnVal;
                          }
                      });
          }
      }
    4. 创建client
      package com.design.design.proxy.dynamic;
      
      
      
      /**
       * @author: GuanBin
       * @date: Created in 上午12:05 2019/7/21
       */
      public class Client {
      
          public static void main(String[] args) {
      
              //创建目标对象(被代理对象)
              ITeacherDao target = new TeacherDao();
      
              //获取代理对象
              ITeacherDao proxyInstance =(ITeacherDao) new ProxyFactory(target).getProxyInstance();
              proxyInstance.teach();
      
              System.out.println("proxyInstance is"+proxyInstance);
              System.out.println("proxyInstance class is"+proxyInstance.getClass());
      
          }
      }
      jdk代理开始
      *****老师正在授课*****
      jdk代理提交
      jdk代理开始
      jdk代理提交
      proxyInstance iscom.design.design.proxy.dynamic.TeacherDao@8efb846
      proxyInstance class isclass com.sun.proxy.$Proxy0
      
      Process finished with exit code 0
      com.sun.proxy.$Proxy0 其中的$说明是代理类
    5. 类图

    四、Cglib代理

    •  静态代理和jdk代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标子类来实现代理,这就是Cglib代理
    • Cglib代理也叫做子类代理,他是在内存中构建一个子类对象从而实现对目标对象功能的扩展,有些书也将Cglib代理归属到动态代理。
    • Cglib是一个很强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口,它广泛的被许多AOP框架使用,例如spring AOP,实现方法拦截
    • Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类

    • 在aop编程中如何选择代理模式

                 1.目标对象需要实现接口,用JDK代理

                 2.目标对象不需要实现接口,用Cglib代理 

         代理的类不能为final,否则报错;

        目标对象的方法,如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法

    1. 创建TeacherDao
      package com.design.design.proxy.cglib;
      
      
      
      /**
       * @author: GuanBin
       * @date: Created in 下午11:56 2019/7/20
       */
      public class TeacherDao  {
          public void teach() {
      
              System.out.println("*****老师正在授课*****");
          }
      }
    2. 创建ProxyFactory
      package com.design.design.proxy.cglib;
      
      import org.springframework.cglib.proxy.Enhancer;
      import org.springframework.cglib.proxy.MethodInterceptor;
      import org.springframework.cglib.proxy.MethodProxy;
      
      import java.lang.reflect.Method;
      
      /**
       * @author: GuanBin
       * @date: Created in 下午1:59 2019/7/21
       */
      public class ProxyFactory implements MethodInterceptor {
      
          private Object target;
      
          public ProxyFactory(Object target){
              this.target=target;
          }
      
      
          /**
           * 返回一个代理对象,是target对象的代理对象
           * @return
           */
          public Object getProxyInstance() {
      
              //构建一个工具类
              Enhancer enhancer = new Enhancer();
              //设置父类
              enhancer.setSuperclass(target.getClass());
              //设置回调函数
              enhancer.setCallback(this);
              //创建子类对象
              return enhancer.create();
      
          }
      
      
          /**
           * 重写intercept方法,会调用目标对象的方法
           */
          @Override
          public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
              System.out.println("调用Cglib代理开始");
              Object invoke = method.invoke(target,objects);
              System.out.println("调用Cglib代理提交");
              return invoke;
          }
      }
    3. 创建Client
      package com.design.design.proxy.cglib;
      
      
      
      
      /**
       * @author: GuanBin
       * @date: Created in 上午12:05 2019/7/21
       */
      public class Client  {
      
          public static void main(String[] args) {
      
              //创建目标对象(被代理对象)
              TeacherDao target = new TeacherDao();
      
              //获取代理对象
              TeacherDao proxyInstance =(TeacherDao) new ProxyFactory(target).getProxyInstance();
              proxyInstance.teach();
      
              System.out.println("proxyInstance is"+proxyInstance);
              System.out.println("proxyInstance class is"+proxyInstance.getClass());
      
          }
      }
    4. 输出
      调用Cglib代理开始
      *****老师正在授课*****
      调用Cglib代理提交
      调用Cglib代理开始
      调用Cglib代理提交
      proxyInstance iscom.design.design.proxy.cglib.TeacherDao@61e717c2
      proxyInstance class isclass com.design.design.proxy.cglib.TeacherDao$$EnhancerByCGLIB$$eae107d1
      
      Process finished with exit code 0

  • 相关阅读:
    golang访问数据库
    dynamic与泛型
    新的published和$M+对比
    插入窗体到别的程序里
    淺談怎么样运用Delphi 2009地泛型容器類別
    Delphi随记
    查找文件
    Delphi操作xml
    Delphi图像编程学习笔记
    Ext.net中如何上传文件
  • 原文地址:https://www.cnblogs.com/guanbin-529/p/11219944.html
Copyright © 2020-2023  润新知