使用TDD手写AOP代码

github地址:GitHub - CodePpoi/spring-code

学习了TDD测试驱动,觉得得拿个东西来练手,想起之前写的AOP一直写不出来,就用测试驱动的方法来完成,没想到还真写出来了。

首先记录自己写测试的时候,列出的代办事项,后面的d表示done,完成的意思

//调用时获得的是代理对象
//先执行实际方法d
//後执行代理对象的方法 before + 1 d
//把代理对象改为JDK代理 d
//调用测试通过 d
//把before和after移动到beforeAdvice和After d
//调用BeforeAdvice和AfterAdvice d
//调用BeforeAdvice和AfterAdvice interceptor d
//用Chain调用 interceptor d
//用JDK代理调用chain d
//使用注解的方式添加advisior buildAdvisor
//添加Before和After注解 

//before advice和 before联系起来
//advisior和before advice联系起来 add
//advice和intecep 联系起来 d

测试通过打印输出来完成,代码

public static void main(String[] args) throws Throwable {

        AnnotationAOPProxyCreator  a = new AnnotationAOPProxyCreator();
        final BizAImpl bizAImpl = new BizAImpl();
        List<Advisor> advisors = a.buildAdvisors();
                //buildAdvisors(BizAImpl.class.getDeclaredMethod("doSomething"));
        JdkDynamicProxyImpl jdkDynamicProxy = new JdkDynamicProxyImpl(advisors, bizAImpl);
        jdkDynamicProxy.invoke(bizAImpl, BizAImpl.class.getDeclaredMethod("doSomething"), null);

        //final IBizA newBizA = (IBizA) createProxy(bizAImpl);
        //newBizA.doSomething();
    }

对应的输出为:

 

其实代理,就是给原对象加了一层List<Advisor> advisors,


        List<Advisor> advisors = a.buildAdvisors();
                //buildAdvisors(BizAImpl.class.getDeclaredMethod("doSomething"));
        JdkDynamicProxyImpl jdkDynamicProxy = new JdkDynamicProxyImpl(advisors, bizAImpl);

那么到底是怎么加的呢,

private List<Advisor> getAdvisorsByAspect(Class class1) {
        List<Advisor> advisors = new ArrayList<>();
        for (Method method : getAdvisorMethods(class1)) {
            Advisor advisor = null;
            try {
                advisor = getAdvisor(method, class1.getAnnotation(Aspect.class));
            } catch (Exception e) {
                //e.printStackTrace();
            }
            if (advisor != null) {
                advisors.add(advisor);
            }
        }
        return advisors;
    }

首先通过getAdvisorMethods获取对应class的所有方法,然后调用getAdivsor

private Advisor getAdvisor(Method method, Object aspect) {
        Advisor advisor = null;
        Advice advice = getAdvice(method, aspect);
        if(advice == null) return advisor;
        advisor = new Advisor();
        advisor.setAspect((Aspect)aspect);
        advisor.setPointcut(getPointcut(method));
        advisor.setAdvice(advice);
        return advisor;
    }

这个方法里有设置advice,advice又是从getAdvice获取的:

private Advice getAdvice(Method method, Object aspect) {
        if(isBefore(method)) {
            return new BeforeAdvice(method, (Aspect) aspect);
        }

        if(isAfter(method)) {
            return new AfterAdvice(method, (Aspect) aspect);
        }

        return null;
    }

也就顺其自然的引入了BeforeAdvice,上面的代码就是把@MyBefore和Advice关联起来,那么标注了@MyBefore的方法也就会执行,intecept方法


public class BeforeAdvice extends Advice implements MyMethodInterceptor {
    public BeforeAdvice(Method adviceMethod, Aspect aspect) {
        super(adviceMethod, aspect);
        // TODO Auto-generated constructor stub
    }



    public void before(final Object target, final Method method, final Object[] args) {
        this.invokeAspectMethod(target, method, args);
    }

    @Override
    public Object intercept(Method method, Object[] arguments, Object target, MethodInterceptorChain chain) {
        //before(target);
        //this.before(target, method, arguments);
        try {
            adviceMethod.invoke(new Logging(), arguments);//第一个参数必为对象实例
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return chain.intercept(method, arguments, target);
    }
}

那么intecept在哪执行:

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MyMethodInterceptor[] iterceptors =
            AdvisorHelper.getMethodInterceptors(this.getAdvisors(), method);
        
        Object obj = new MethodInterceptorChain(iterceptors)
                        .intercept(method,args,proxy);
        return obj;
    }

就是在jdk代理执行invoke方法是,会先根据Adivsor获取一个拦截器组,然后顺着这个责任链,一步一步的调用下去,也就会执行到BeforeAdvice里面了。

TDD最常用的就是伪实现,也正是这个技巧让我成功实现了AOP,不然头都是晕的=.=

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值