手写spring框架预备知识:责任链模式解决cglib多重代理问题

cglib在动态代理时,无法像jdk动态代理那样对代理对象再次执行代理。

问题原理分析参考博客CGLIB-多重代理

整合自己的手写spring

        在进行动态代理时,如果该类有接口,则进行jdk动态代理,如果没有接口,则取执行cglib的动态代理逻辑,其中jdk动态代理过程如下:

private Object jdkDynamicProxy(Class<?> clazz, Object bean) {
        for (AopProcessor aopProcessor : aopProcessors) {
            String pointCut = aopProcessor.getPointCut();
            if (BeanUtils.aopMatch(pointCut, clazz.getName())) {
                JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(bean, aopProcessor);
                //如果有接口,使用jdk动态代理
                bean = jdkDynamicProxy.getProxyBean();
            }
        }
        return bean;
    }

直接对bean进行反复代理和赋值即可。

        对于cglib代理来说,则需要使用责任链模式,将aop类封装成责任链执行者,然后在代理类中执行该责任链即可,实现代码如下:

定义调用链方法:

public interface CglibPoint {
    //处理代理对象的代理功能,是责任链的调用链方法
    Object proceed(CglibChain chain, Method method, Object[] args);
}

定义责任链对象

public class CglibChain {
    //切面链
    private List<CglibPoint> cglibPoints;

    //责任链开始的位置
    private int idx = -1;
    //被代理对象
    private Object target;

    public CglibChain(Object target) {
        this.target = target;
        this.cglibPoints = new ArrayList<>();
    }

    public void registCglibPoint(CglibPoint cglibPoint) {
        cglibPoints.add(cglibPoint);
    }

    /**
     * 执行代理链
     * @param method 被代理方法
     * @param args 被代理方法参数
     * @return
     */
    public Object process(Method method, Object[] args) {
        Object res = null;
        //没有责任链了就直接返回
        if (++idx ==cglibPoints.size()){
            try {
                res = method.invoke(target, args);
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
//            System.out.println("cglib代理结束");
        }else {
            res = cglibPoints.get(idx).proceed(this, method, args);
        }
        return res;
    }

    public void resetIdx() {
        this.idx = -1;
    }
}

代理类对象

public class CglibProxy implements MethodInterceptor {
    //被代理类
    private Object target;
    //由于cglib不能多重代理,所以将所有的代理功能放在一个责任链中执行
    private CglibChain cglibChain;

    public CglibProxy(Object target) {
        this.target = target;
        this.cglibChain = new CglibChain(target);
    }

    /**
     * 将aop方法转化为责任链并注册到责任链对象中
     * @param aopProcessor aop类
     */
    public void registCglibPoint(AopProcessor aopProcessor) {
        cglibChain.registCglibPoint(new CglibPoint() {
            @Override
            public Object proceed(CglibChain chain, Method method, Object[] args) {
                Object res = null;
                try {
                    Object newInstance = aopProcessor.getClazz().getConstructor().newInstance();
                    //将切面信息包装成ProceedingJoinPoint对象
                    ProceedingJoinPoint joinPoint = new ProceedingJoinPoint();
                    joinPoint.load(target);
                    //增强前方法
                    Method beforeMethod = aopProcessor.getBeforeMethod();
                    if (beforeMethod != null) beforeMethod.invoke(newInstance,joinPoint);
                    //执行本方法
                    res = chain.process(method, args);
                    //增强后方法
                    Method afterMethod = aopProcessor.getAfterMethod();
                    if (afterMethod != null) afterMethod.invoke(newInstance,joinPoint);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                return res;
            }
        });
    }

    /**
     * 获取代理对象
     * @return
     */
    public Object getProxyBean() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        Object o = enhancer.create();
        return o;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        cglibChain.resetIdx();
        return cglibChain.process(method, objects);
    }
}

AOP部分代码:

     /**
     * cglib无法多重代理,需要转换为拦截器链模式来实现
     *
     * @param clazz
     * @param bean
     * @return
     */
    private Object cglibProxy(Class<?> clazz, Object bean) {
        //没有接口用cglib
        CglibProxy cglibProxy = new CglibProxy(bean);
        //注册所有的Aop,因为cglib不能多重代理
        for (AopProcessor aopProcessor : aopProcessors) {
            String pointCut = aopProcessor.getPointCut();
            if (BeanUtils.aopMatch(pointCut, clazz.getName())) {
                cglibProxy.registCglibPoint(aopProcessor);
            }
        }
        bean = cglibProxy.getProxyBean();

        return bean;
    }

结果:

源码地址:

https://gitee.com/cg--cg/framework

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值