zoukankan      html  css  js  c++  java
  • 1.【设计模式.结构型.代理模式】代理模式的的实现

    设计模式.结构型.代理模式

    一、说明:

    代理模式是为了增强被代理对象(目标对象)的方法,可在不改变目标对象的代码情况下对其方法进行增强。遵循了开闭原则。spring框架中的AOP就是基于代理模式开发。实现方法相对固定。

    二、静态代理

    显式地描述出具体的目标对象,需要代理对象和目标对象都实现同一个接口。

    package com.fatsea.news.pattern.structural;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    /**
     * @Author: Chunhai.Hu
     * @Date: 2021/4/28 16:02
     * @Desc: 代理模式(CGLib动态代理方式)测试
     * 被代理对象不必实现某个接口即可进行代理
     * CGLIB原理:继承目标对象,重写目标对象的方法
     */
    public class CglibProxyTest {
        public static void main(String[] args) {
            RealPerson target = new RealPerson();
            RealPerson proxy  = new CglibRealPerson(target).createProxy();
            proxy.sayHello("我是CGLib代理的对象");
            proxy.sayHi("小王", "我是最可爱的人");
        }
    }
    
    // 代理对象:实现MethodInterceptor接口即可
    class CglibRealPerson implements MethodInterceptor {
    
        private RealPerson target;
    
        public CglibRealPerson(RealPerson target) {
            this.target = target;
        }
    
        /**
         * @对外暴露代理对象
         * @return
         */
        public RealPerson createProxy () {
            Enhancer enhancer = new Enhancer();
            // 指定父类
            enhancer.setSuperclass(RealPerson.class);
            // 指定回调方法
            enhancer.setCallback(this);
            // 返回代理对象
            return (RealPerson) enhancer.create();
        }
    
        private int i = 0;
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("invoke第:" + ++i + "次执行。");
            System.out.println("执行的方法名称:" + method.getName());
    
            System.out.println("代理之前执行的方法" + i);
            method.invoke(target, objects);
            System.out.println("代理之后执行的方法" + i);
            return null;
        }
    }
    
    // 目标对象:没有实现任何接口
    class RealPerson {
        public void sayHello (String word) {
            System.out.println(word);
        }
    
        public void sayHi (String name, String word) {
            System.out.println("我是:" + name + "***说:***" + word);
        }
    }
    

    三、JDK代理

    为原生的JDK开发包中所包含的代理实现API,需要代理对象和目标对象都实现同一个接口(如下实例中复用了上面目标对象)。

    package com.fatsea.news.pattern.structural;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * @Author: Chunhai.Hu
     * @Date: 2021/4/28 11:58
     * @Desc: 代理模式(JDK动态代理方式)测试
     * 使用前提:被代理对象必须实现某个接口
     */
    public class JdkProxyTest {
        public static void main(String[] args) {
            // 被代理对象(目标对象)
            Subject target = new RealSubject();
            // 被代理对象的调用处理器
            InvocationHandler invocationHandler = new TargetInvocationHandler(target);
            // 代理对象
            Subject proxy = (Subject) Proxy.newProxyInstance(
                            target.getClass().getClassLoader(),
                            target.getClass().getInterfaces(),
                            invocationHandler);
    
            // 使用代理对象调用被代理对象的方法
            proxy.sayHello("大家好,我是可爱的小宝贝!");
            proxy.sayHi("小胡", "我是万人迷");
        }
    }
    
    class TargetInvocationHandler implements InvocationHandler {
    
        private Object target;
    
        public TargetInvocationHandler(Object target) {
            this.target = target;
        }
    
        private int i = 0;
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("invoke第:" + ++i + "次执行。");
            System.out.println("执行的方法名称:" + method.getName());
    
            // 可根据方法名对不同的方法进行增强
            String methodName = method.getName();
            if (methodName.equals("sayHi")) {
                System.out.println("代理之前执行的方法" + i);
                // 执行代理类的方法
                method.invoke(target, args);
                System.out.println("代理之后执行的方法" + i);
            } else {
                // 不增强被代理对象方法
                method.invoke(target, args);
            }
            return null;
        }
    }
    

    四、CGLib代理

    • 以上两种代理模式使用前提都是需要代理对象和目标对象同时实现同一个接口,实际开发中有可能目标对象没有实现任何接口。而CGLib开发包就是为了应对这种情况。它采用继承目标对象的方式实现了代理功能。

    • 需要依赖如下开发包:

      	<!--springframework中已经包含此包,重复导入会导致java.lang.VerifyError错误-->
          <dependency>
          <groupId>cglib</groupId>
          <artifactId>cglib</artifactId>
          <version>${cglib.version}</version>
          </dependency>
      
    package com.fatsea.news.pattern.structural;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    /**
     * @Author: Chunhai.Hu
     * @Date: 2021/4/28 16:02
     * @Desc: 代理模式(CGLib动态代理方式)测试
     * 被代理对象不必实现某个接口即可进行代理
     * CGLIB原理:继承目标对象,重写目标对象的方法
     */
    public class CglibProxyTest {
        public static void main(String[] args) {
            RealPerson target = new RealPerson();
            RealPerson proxy  = new CglibRealPerson(target).createProxy();
            proxy.sayHello("我是CGLib代理的对象");
            proxy.sayHi("小王", "我是最可爱的人");
        }
    }
    
    // 代理对象:实现MethodInterceptor接口即可
    class CglibRealPerson implements MethodInterceptor {
    
        private RealPerson target;
    
        public CglibRealPerson(RealPerson target) {
            this.target = target;
        }
    
        /**
         * @对外暴露代理对象
         * @return
         */
        public RealPerson createProxy () {
            Enhancer enhancer = new Enhancer();
            // 指定父类
            enhancer.setSuperclass(RealPerson.class);
            // 指定回调方法
            enhancer.setCallback(this);
            // 返回代理对象
            return (RealPerson) enhancer.create();
        }
    
        private int i = 0;
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("invoke第:" + ++i + "次执行。");
            System.out.println("执行的方法名称:" + method.getName());
    
            System.out.println("代理之前执行的方法" + i);
            method.invoke(target, objects);
            System.out.println("代理之后执行的方法" + i);
            return null;
        }
    }
    
    // 目标对象:没有实现任何接口
    class RealPerson {
        public void sayHello (String word) {
            System.out.println(word);
        }
    
        public void sayHi (String name, String word) {
            System.out.println("我是:" + name + "***说:***" + word);
        }
    }
    
  • 相关阅读:
    C# 抽象方法和虚方法的区别
    xmlhttprequest readyState 属性的五种状态
    ServiceStack破解文件
    k8s部署mysql
    docker 开放2376端口的问题
    .net core 发布到IIS 没有 web.config 文件
    1064
    docker mysql 主从同步配置
    Docker 鼠标在虚拟机与主机之间自由切换
    Socket原理解析2
  • 原文地址:https://www.cnblogs.com/Nick-Hu/p/14714963.html
Copyright © 2011-2022 走看看