JDK动态代理CGLIB动态代理

Posted zqq_hello_world

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK动态代理CGLIB动态代理相关的知识,希望对你有一定的参考价值。

JDK动态代理

JDK动态代码是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产出代理对象。

  1. 定义一个接口

    /**
     * 定义接口,JDK动态代理必须借助一个接口才能产生代理对象
     */
    public interface HelloService {
    
        void sayHelloWorld();
    }
    
  2. 创建接口实现类

    /**
     * 实现类
     */
    public class HelloServerImpl implements HelloService {
        @Override
        public void sayHelloWorld() {
            System.out.println("线程:" + Thread.currentThread().getName() + " say Hello World");
        }
    }
    
  3. 创建代理对象

    JDK动态代理中,代理对象必须要实现代理逻辑必须实现 java.lang.reflect.InvocationHandler 接口,实现invoke()方法

    /**
     * 代理对象
     * JDK动态代理中,要实现代理逻辑必须实现 java.lang.reflect.InvocationHandler 接口
     */
    public class JdkProxy implements InvocationHandler {
    
    
        /**
         * 真实对象
         */
        private Object target = null;
    
        /**
         * 绑定代理对象和真实对象的代理关系,并返回代理对象。这一步主要是代理对象和真实对象关系
         * @param object
         * @return
         */
        public Object bind(Object object){
            this.target = object;
            //1.第一个参数是类加载器object.getClass(),这里采用的是object本身的类加载器
            //2.第二个参数是动态代理对象下挂在哪些接口下。object.getClass().getInterfaces()这个方法是通过反射获取实现的接口,object是真实对象,也就是获取真实对象继承的接口
            //3.第三个是传入代理类。代理类必须实现InvocationHandler接口,重写代理类逻辑方法invoke()
            return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
        }
    
        /**
         * 代理方法逻辑处理方法
         * @param proxy 代理对象,上面bind方法产生的对象
         * @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("在调用真实对象之前的逻辑输出 =。=");
            //调用真实对象的代理方法,这里相当于调用sayHelloWorld方法,看外部代理类调用哪个方法
            Object object = method.invoke(target,args);
            System.out.println("在调用真实对象之后的输出 =_=");
            return object;
        }
    }
    
  4. JDK动态代理调用测试

    public class Test {
    
        /**
         * JDK动态代理测试
         * @param args
         */
        public static void main(String[] args) {
            //1.创建代理对象
            JdkProxy jdkProxy = new JdkProxy();
            //2.代理对象与真实对象绑定,因为挂在HelloService接口下,所以可以用HelloService去引用
            HelloService helloService = (HelloService) jdkProxy.bind(new HelloServerImpl());
            //3.helloService实际引用的是一个代理对象,会进入到代理对象的invoke方法。invoke里面调用真实对象的方法,前后加上自己的逻辑
            helloService.sayHelloWorld();
        }
    }
    

    输出结果,在调用真实对象的方法前后执行了代理方法的逻辑

    Connected to the target VM, address: '127.0.0.1:61305', transport: 'socket'
    进入代理逻辑方法====================
    在调用真实对象之前的逻辑输出 ==
    线程:main say Hello World
    在调用真实对象之后的输出 =_=
    Disconnected from the target VM, address: '127.0.0.1:61305', transport: 'socket'
    

CGLIB动态代理

JDK动态代理必须提供接口才能使用,在一些不能提供接口的环境中,只能采用其他第三方技术,比如CGLIB动态代理。它的优势在于不需要提供接口,只要一个非抽象类就能实现动态代理

  1. CGLIB是第三方实现,引入Jar包

    <dependency>
       <groupId>cglib</groupId>
       <artifactId>cglib</artifactId>
       <version>3.3.0</version>
    </dependency>
    
  2. 创建一个类

    /**
     * 创建cglib动态代理测试类,不需要实现接口
     */
    public class CglibImpl {
    
        /**
         * 创建一个测试方法,通过CGLIB动态代理调用此方法
         */
        public void sayHelloWorld(){
            System.out.println("CGLIB,线程:" + Thread.currentThread().getName() + " say Hello World");
        }
    }
    
    
  3. 创建CGLIB代理类

    /**
     * 创建CGLIB动态代理的代理类,实现CGLIB的MethodInterceptor接口
     */
    public class CglibProxy implements MethodInterceptor{
    
    
        /**
         * 生成CGLIB代理对象
         * @param cls
         * @return
         */
        public Object getProxy(Class cls){
            //CGLIB Enhancer 增强类对象
            Enhancer enhancer = new Enhancer();
            //设置增强类
            enhancer.setSuperclass(cls);
            //定义代理逻辑对象为当前对象,当前对象必须实现net.sf.cglib.proxy.MethodInterceptor接口
            enhancer.setCallback(this);
            //生成并返回代理对象
            return enhancer.create();
        }
    
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("调用真实对象前===============");
            //调用真实对象方法
            Object result = methodProxy.invokeSuper(o,objects);
            System.out.println("调用真实对象后===============");
            return result;
        }
    }
    
  4. CGLIB代理测试

    public class Test {
    
        public static void main(String[] args) {
            //创建cglib代理对象
            CglibProxy cglibProxy = new CglibProxy();
            //获取代理对象,getProxy()返回的是一个代理对象
            CglibImpl cglibImpl = (CglibImpl) cglibProxy.getProxy(CglibImpl.class);
            //调用方法,走代理对象处理逻辑
            cglibImpl.sayHelloWorld();
        }
    }
    

    输出结果

    Connected to the target VM, address: '127.0.0.1:65050', transport: 'socket'
    调用真实对象前===============
    CGLIB,线程:main say Hello World
    调用真实对象后===============
    Disconnected from the target VM, address: '127.0.0.1:65050', transport: 'socket'
    

以上是关于JDK动态代理CGLIB动态代理的主要内容,如果未能解决你的问题,请参考以下文章

代理模式(静态代理jdk动态代理CGLib动态代理)

jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)

JDK动态代理与Cglib动态代理

(java反射-JDK动态代理)+CGLIB动态代理

性能优于JDK代理,CGLib如何实现动态代理

JDK动态代理和 CGLIB 代理