还不会写cglib多重代理?你out了,我来教你写

437 阅读2分钟

场景

众说周知cglib实现的代理只能被代理一次,二次代理就会抛出异常,然而Spring Aop却可以对一个方法多次拦截。这里面用了什么黑科技呢,让我们一起来看看吧

依赖

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

被代理对象

/**
 * @author caohu
 * @version 1.0
 * @date 2022/2/21 10:14 AM
 */
public class OrderService {
    private Object orderDao;
    public String getOrder(Long id) {
        System.out.println("获取了订单" + id);
        return "order" + id;
    }
    public void addOrder(Long id) {
        System.out.println("添加了订单" + id);
    }
    public void setOrderDao(Object orderDao) {
        this.orderDao = orderDao;
    }
    public Object getOrderDao() {
        return this.orderDao;
    }
}

定义拦截器接口

import java.lang.reflect.Method;

/**
 * @author caohu
 * @version 1.0
 * @date 2022/2/23 6:47 PM
 */
public interface ProxyInterceptor {

    /**
     * 是否拦截
     * @param target
     * @param args
     * @param method
     * @return
     */
    default boolean accept(Object target, Object[] args, Method method) {
        return true;
    }

    /**
     * 代理执行
     * @param target
     * @param args
     * @param method
     * @param proxyInterceptorChain
     * @return
     * @throws Throwable
     */
    Object invoke(Object target, Object[] args, Method method, ProxyInterceptorChain proxyInterceptorChain) throws Throwable;

}

定义拦截器链

import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author caohu
 * @version 1.0
 * @date 2022/2/24 4:02 PM
 */
public class ProxyInterceptorChain {
    private int i;
    private List<ProxyInterceptor> proxyInterceptors;
    private MethodProxy methodProxy;
    public ProxyInterceptorChain(List<ProxyInterceptor> proxyInterceptors, MethodProxy methodProxy) {
        i = proxyInterceptors.size();
        this.proxyInterceptors = proxyInterceptors;
        this.methodProxy = methodProxy;
    }
    public Object chain(Object target, Object[] args, Method method) throws Throwable {
        if (0 == i) {
            return methodProxy.invokeSuper(target, args);
        }
        ProxyInterceptor proxyInterceptor = proxyInterceptors.get(--i);
        if (!proxyInterceptor.accept(target, args, method)) {
            return chain(target, args, method);
        }
        return proxyInterceptor.invoke(target, args, method, this);
    }
}

代理工具类

import org.springframework.aop.SpringProxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.cglib.proxy.CallbackHelper;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author caohu
 * @version 1.0
 * @date 2022/2/23 6:45 PM
 */
public class ProxyUtil {

    private static final Map<Class<?>, List<ProxyInterceptor>> PROXY_INTERCEPTOR_CHAIN_MAP = new ConcurrentHashMap<>(16);

    public static Object proxy(Object target, ProxyInterceptor proxyInterceptor) {
        // 如果已经被代理过了 则只加入拦截器链中
        if (AopUtils.isCglibProxy(target)) {
            Class<?> clazz = target.getClass();
            while (clazz != null) {
                List<ProxyInterceptor> proxyInterceptors = PROXY_INTERCEPTOR_CHAIN_MAP.get(clazz);
                if (null != proxyInterceptors) {
                    proxyInterceptors.add(proxyInterceptor);
                    return target;
                }
                clazz = clazz.getSuperclass();
            }
            throw new RuntimeException();
        }

        List<ProxyInterceptor> proxyInterceptors = new ArrayList<>();
        proxyInterceptors.add(proxyInterceptor);
        PROXY_INTERCEPTOR_CHAIN_MAP.put(target.getClass(), proxyInterceptors);

        Class<?> clazz = target.getClass();
        CallbackHelper callbackHelper = new CallbackHelper(clazz, new Class[0]) {
            @Override
            protected Object getCallback(Method method) {
                return (MethodInterceptor) (o, method1, objects, methodProxy) -> {
                    ProxyInterceptorChain chain = new ProxyInterceptorChain(proxyInterceptors, methodProxy);
                    return chain.chain(o, objects, method1);
                };
            }
        };

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        // 标识为spring代理
        enhancer.setInterfaces(new Class[]{SpringProxy.class});
        // 原对象的字段值不会被保留
        return enhancer.create();
    }

}

代理测试

import com.ch.my.demo.proxy.service.OrderService;
import com.ch.my.demo.proxy.service.component.ProxyInterceptor;
import com.ch.my.demo.proxy.service.component.ProxyInterceptorChain;
import com.ch.my.demo.proxy.service.component.ProxyUtil;
import org.junit.Test;
import java.lang.reflect.Method;

/**
 * @author caohu
 * @version 1.0
 * @date 2022/2/23 6:52 PM
 */
public class TestProxyUtil {

    @Test
    public void testProxyUtil() {
        OrderService orderService = new OrderService();
        // 被代理后原对象字段值不会保留
        orderService.setOrderDao(new Object());
        // 第一次代理
        orderService = (OrderService) ProxyUtil.proxy(orderService, new ProxyInterceptor() {
            @Override
            public boolean accept(Object target, Object[] args, Method method) {
                return args[0].equals(1L);
            }

            @Override
            public Object invoke(Object target, Object[] args, Method method, ProxyInterceptorChain proxyInterceptorChain) throws Throwable {
                System.out.println("orderService1-Before");
                Object result = proxyInterceptorChain.chain(target, args, method);
                System.out.println("orderService1-After");
                return result;
            }
        });
        //第二次代理
        orderService = (OrderService) ProxyUtil.proxy(orderService, new ProxyInterceptor() {
            @Override
            public boolean accept(Object target, Object[] args, Method method) {
                return args[0].equals(1L);
            }
            @Override
            public Object invoke(Object target, Object[] args, Method method, ProxyInterceptorChain proxyInterceptorChain) throws Throwable {
                System.out.println("orderService2-Before");
                Object result = proxyInterceptorChain.chain(target, args, method);
                System.out.println("orderService2-After");
                return result;
            }
        });
        orderService.getOrder(1L);
    }

}

输出

orderService2-Before
orderService1-Before
获取了订单1
orderService1-After
orderService2-After