• Java的代理proxy机制


    2021-02-03

    Java的代理proxy机制

    代理必须分为两个步骤:
     * 1. 代理对象和真实对象建立代理关系
     * 2. 实现代理对象的代理逻辑方法

    主要是通过两种方法:

    1. JDK动态代理

    JDK动态代理是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象,所以先定义接口。JDK动态代理中,要实现代理逻辑类必须去实现java.lang.reflect.InvocationHandler接口,

    它里面定义了一个invoke方法,并提供接口数组用于下挂代理对象。

    2. CGLIB动态代理

    CGLIB动态代理,它的优势在于不需要提供接口,只要一个非抽象类就能实现动态代理。

    但需要引入jar包或者 maven 的 pom.xml中添加:

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.3.0</version>
    </dependency>

    1. JDK动态代理

    我们通过代码来看,主要包括4个java文件。

    HelloWorld:测试文件接口
    HelloWorldImpl:测试文件的实现
    JdkProxyExample:实现代理
    TestJdkProxy:测试代理

    1) HelloWorld 测试文件接口

    package cn.zc.javapro.mechanism.proxy.jdk;
    
    public interface HelloWorld {
        public void sayHelloWorld();
    }

    2)HelloWorldImpl 测试文件的实现

    package cn.zc.javapro.mechanism.proxy.jdk;
    
    public class HelloWorldImpl implements HelloWorld {
    
        @Override
        public void sayHelloWorld() {
            System.out.println("Hello World!");
        }
    
    }

    3)JdkProxyExample:实现代理

    package cn.zc.javapro.mechanism.proxy.jdk;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /*
     * 代理必须分为两个步骤:
     * 1. 代理对象和真实对象建立代理关系
     * 2. 实现代理对象的代理逻辑方法
     */
    
    /*
     * JDK动态代理是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象,所以先定义接口。
     */
    
    /*
     * JDK动态代理中,要实现代理逻辑类必须去实现java.lang.reflect.InvocationHandler接口,
     * 它里面定义了一个invoke方法,并提供接口数组用于下挂代理对象。
     */
    
    public class JdkProxyExample implements InvocationHandler {
    
        //真实对象
        private Object target = null;
        
        /**
         * 1. 建立代理对象和真实对象的代理关系,并返回代理对象
         * @param target 真实对象
         * @return 代理对象
         */
        public Object bind(Object target) {
            this.target = target;
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                    target.getClass().getInterfaces(), this);
        }
        
        /**
         * 2.代理方法逻辑
         * @param proxy 代理对象
         * @param method 当前调度方法
         * @param args 当前方法参数
         * @return 代理结果返回
         * @throws Throwable 异常
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("进入代理逻辑方法");
            System.out.println("在调度真实对象之前的服务");
            Object obj = method.invoke(target, args); //相当于调用sayHelloWorld方法
            System.out.println("在调度真实对象之后的服务");
            return obj;
        }
    
    }
    JdkProxyExample

    4)TestJdkProxy:测试代理

    package cn.zc.javapro.mechanism.proxy.jdk;
    
    public class TestJdkProxy {
    
        public static void main(String[] args) {
            JdkProxyExample jdk = new JdkProxyExample();
            //绑定关系,因为挂在接口HelloWorld下,所以声明代理对象HelloWorld proxy
            HelloWorld proxy = (HelloWorld)jdk.bind(new HelloWorldImpl());
            //注意,此时HelloWorld对象已经是一个代理对象,它会进入代理的逻辑方法invoke里
            proxy.sayHelloWorld();
            //相当于下面这段代码
            /*
            try {
                jdk.invoke(proxy, HelloWorldImpl.class.getMethod("sayHelloWorld", null), null);
            } catch (Throwable e) {
                e.printStackTrace();
            }*/
        }
    
    }

    2. CGLIB动态代理

    我们通过代码来看,主要包括3个java文件。

    HelloImpl:测试类

    CglibProxyExample :代理实现类

    TestCGLIBProxy:测试代理类

    1)HelloImpl:测试类

    package cn.zc.javapro.mechanism.proxy.cglib;
    
    public class HelloImpl {
        public void sayHello(String name) {
            System.out.println("Hello " + name);
        }
    }

    2)CglibProxyExample :代理实现类

    package cn.zc.javapro.mechanism.proxy.cglib;
    
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    /*
     * 代理必须分为两个步骤:
     * 1. 代理对象和真实对象建立代理关系
     * 2. 实现代理对象的代理逻辑方法
     */
    /*需要引入
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.3.0</version>
    </dependency>
    */
    // CGLIB动态代理,它的优势在于不需要提供接口,只要一个非抽象类就能实现动态代理
    
    public class CglibProxyExample implements MethodInterceptor {
        
        /**
         * 生成CGLIB代理对象
         * @param cls -- Class类
         * @return Class类的CGLIB代理对象
         */
        public Object getProxy(Class cls) {
            //CGLIB enhancer 增强类对象
            Enhancer enhancer = new Enhancer();
            // 设置增强类型
            enhancer.setSuperclass(cls);
            // 定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
            enhancer.setCallback(this);
            // 生成并返回代理对象
            return enhancer.create();
        }
        
        /**
         * 代理逻辑方法
         * @param proxy 代理对象
         * @param method 方法
         * @param args 方法参数
         * @param methodProxy 方法代理
         * @return 代理逻辑返回
         * @throws Throwable 异常
         */
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("调用真实对象前");
            // CGLIB 反射调用真实对象方法
            Object result = methodProxy.invokeSuper(proxy, args);
            System.out.println("调用真实对象后");
            return result;
        }
    
    }
    CglibProxyExample

    3)TestCGLIBProxy:测试代理类

    package cn.zc.javapro.mechanism.proxy.cglib;
    
    public class TestCGLIBProxy {
    
        public static void testCGLIBProxy() {
            CglibProxyExample cpe = new CglibProxyExample();
            HelloImpl obj = (HelloImpl)cpe.getProxy(HelloImpl.class);
            obj.sayHello("zhangsan");
        }
        
        public static void main(String[] args) {
            testCGLIBProxy();
        }
    
    }
  • 相关阅读:
    编译Openmv固件&增加串口
    边缘 AI 平台的比较
    CVPR2021 | 重新思考BatchNorm中的Batch
    ICCV2021 |重新思考人群中的计数和定位:一个纯粹基于点的框架
    ICCV2021 | 重新思考视觉transformers的空间维度
    CVPR2021 | Transformer用于End-to-End视频实例分割
    漫谈CUDA优化
    AAAI 2021 最佳论文公布
    综述专栏 | 姿态估计综述
    为什么GEMM是深度学习的核心
  • 原文地址:https://www.cnblogs.com/zhangchao0515/p/14370163.html
Copyright © 2020-2023  润新知