代理模式

一、代理模式的基本介绍

  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

 

posted @ 2019-07-21 00:41  纵码万水千山  阅读(138)  评论(0编辑  收藏  举报