java代理模式

读mybatis源代码时,看到mybatis通过jdk动态代理mapper来实现它的CRUD。因为日常工作中比较少用到代理模式。所以对这一块并不熟悉。

闲暇之余,翻阅了一些资料和例子了解了一下。做了个demo、记录一点笔记。

package com.boot.demo.test.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author braska
 * @date 2020/3/13
 **/
public class ProxyTest {

    interface IService {
        void call(String word);
    }

    static class ServiceImpl implements IService {
        @Override
        public void call(String word) {
            System.out.println(word);
        }
    }

    /**
     * 静态代理
     */
    static class ServiceStaticProxy implements IService {
        private IService service;
        public ServiceStaticProxy(IService service) {
            this.service = service;
        }

        @Override
        public void call(String word) {
            System.out.println("static: before call().");
            service.call(word);
            System.out.println("static: after call().");
        }
    }

    /**
     * jdk动态代理的方法处理器
     * @param <T>
     */
    static class ServiceHandler<T> implements InvocationHandler {
        private T t;
        public ServiceHandler(T t) {
            this.t = t;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("jdk: before call().");
            Object obj = method.invoke(t, args);
            System.out.println("jdk: after call().");
            return obj;
        }
    }

    /**
     * jdk动态代理类
     * @param <T>
     */
    static class ServiceJdkProxy<T> {
        private T t;
        private ServiceHandler handler;
        public ServiceJdkProxy(T t, ServiceHandler handler) {
            this.t = t;
            this.handler = handler;
        }

        public T newProxyInstance() {
            return (T)Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), handler);
        }
    }

    /**
     * cglib动态代理,需引入cglib依赖包
     * @param <T>
     */
    static class ServiceCglibProxy<T> implements MethodInterceptor {
        private T t;
        public ServiceCglibProxy() {}
        public ServiceCglibProxy(T t) {
            this.t = t;
        }

        public T newProxyInstance() {
            Enhancer en = new Enhancer();
            en.setSuperclass(t.getClass());
            en.setCallback(this);
            return (T)en.create();
        }

        public T newProxyInstance(T t) {
            Enhancer en = new Enhancer();
            en.setSuperclass(t.getClass());
            en.setCallback(this);
            return (T)en.create();
        }

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("cglib: before call().");
            //Object obj = method.invoke(t, objects);
            Object obj = methodProxy.invokeSuper(o, objects);  //推荐
            System.out.println("cglib: after call().");
            return obj;
        }
    }

    public static void main(String[] args) {
        IService service = new ServiceImpl();
        service.call("normal called.");

        // static static.
        long time1 = System.currentTimeMillis();
        ServiceStaticProxy staticProxy = new ServiceStaticProxy(service);
        staticProxy.call("static proxy called.");
        System.out.println("静态代理调用时间:" + (System.currentTimeMillis() - time1));

        // jdk proxy
        time1 = System.currentTimeMillis();
        ServiceHandler handler = new ServiceHandler(service);
        IService proxyService = new ServiceJdkProxy<>(service, handler).newProxyInstance();
        proxyService.call("jdk proxy called.");
        System.out.println("jdk动态代理调用时间:" + (System.currentTimeMillis() - time1));

        // cglib proxy
        time1 = System.currentTimeMillis();
        //IService cgLibProxyService = new ServiceCglibProxy<>(service).newProxyInstance();
        IService cgLibProxyService = new ServiceCglibProxy<IService>().newProxyInstance(service);
        cgLibProxyService.call("cglib proxy called.");
        System.out.println("cglib动态代理调用时间:" + (System.currentTimeMillis() - time1));

    }
}

 控制台输出:

normal called.
static: before call().
static proxy called.
static: after call().
静态代理调用时间:1
jdk: before call().
jdk proxy called.
jdk: after call().
jdk动态代理调用时间:8
cglib: before call().
cglib proxy called.
cglib: after call().
cglib动态代理调用时间:121

从结果可以看出jdk动态代理整个过程调用耗时远低于gclib动态代理。但这并不能表示jdk性能比cglib动态代理好。事实上,cglib执行速度略快于jdk代理。jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码。cglib执行速度略大于jdk,所以比较适合单例模式。另外由于CGLIB的大部分类是直接对Java字节码进行操作,这样生成的类会在Java的永久堆中。如果动态代理操作过多,容易造成永久堆满,触发OutOfMemory异常。spring默认使用jdk动态代理,如果类没有接口,则使用cglib。

原文地址:https://www.cnblogs.com/braska/p/12486344.html