一、非注解式简易版AOP
整体流程
1.1 代码
public class Test {public static void main(String[] args){// Aop代理工厂DefaultAopProxyFactory factory = new DefaultAopProxyFactory();// 测试对象AOPDemoImpl demo = new AOPDemoImpl();// 支撑类:用于存放目标对象、各种通知以及目标对象的接口AdvisedSupport advisedSupport = new AdvisedSupport();advisedSupport.setTarget(demo);// 生成三个通知类,分别代表环绕通知,前置通知和后置通知Advice logAdvice = new LogAdvice();Advice beforeAdvice = new BeforeAdvice();Advice afterAdvice = new AfterAdvice();// 通知器:将切入点和通知连接起来,是对切面的实现Advisor advisor1 = new DefaultPointcutAdvisor(null, logAdvice, "0");Advisor advisor2 = new DefaultPointcutAdvisor(null, beforeAdvice, "1");Advisor advisor3 = new DefaultPointcutAdvisor(null, afterAdvice, "2");advisedSupport.addAroundAdvisors(advisor1);advisedSupport.addBeforeAdvisors(advisor2);advisedSupport.addAfterAdvisors(advisor3);Class<?>[] interfaces = demo.getClass().getInterfaces();advisedSupport.setInterfaces(interfaces);// 构建代理对象AopProxy aopProxy = factory.createAopProxy(advisedSupport);AOPDemo proxyObj = (AOPDemo) aopProxy.getProxy();// 执行方法proxyObj.send();}
}
这种AOP实现方式,没有借助注解,并且也不像Spring官方代码中,通知类型可以细化到方法上。
可以看出目前实现方式还是在类的层面,每一个类被定义为是环绕通知还是前置等。
此外,也没有涉及到切入点的实现,不过通过这个简易版AOP,可以帮助我们更好的理解AOP的实现原理。
1.2 关键类和接口
- 通知链:一个或多个List;
- Advice:通知,表示增强的功能;
- MethodInvocation:方法调用,用来对通知链中的通知进行依次调用;
- MethodInterceptor:方法拦截器,被
MethodInvocation
调用后,执行对应的通知,之后再调用回MethodInvocation
。
1.2.1 通知链
其实本质就是一个List
,包括前置通知链、环绕通知链和后置通知链。
通知链中存放的是一个一个的通知类。
执行顺序为:前环绕通知—>前置通知—>目标方法—>后置通知—>后环绕通知。
实现的难点:怎么将环绕通知分开呢?前置/后置我们可以根据方法放置在目标方法的前面或后面来实现。对于环绕通知是一个方法,我们怎么将内部的代码分成两部分呢?
要实现这个需求,我们应该使用递归。当我们检测到要执行环绕通知后,会在进入到环绕通知内部执行后续所有操作,直到全部通知执行完成,才会从环绕通知中出来。
1.2.2 Advice
Advice:通知,表示增强的功能。我们根据情况定义了三个子接口。
实现这些接口的类,就是通知类。
值得注意的是:
before
和after
都是无参的方法,而around
需要传递一个ProceedingJoinPoint
对象。环绕通知比较特殊,它需要先执行前一部分通知,再执行目标方法(或before–>target),最后执行后一部分通知
基于此,我们应该在环绕通知内部进行通知链调用。其实
ProceedingJoinPoint
正是MethodInvocation
的封装。这一点,我们后面会讲到。
pjp.proceed()
内部执行的是通知链调用,会执行后续的通知,等全部执行完毕,就会回调执行后环绕。public class BeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before() throws Throwable {System.out.println("-----before-----");} } public class LogAdvice implements MethodAroundAdvice {@Overridepublic Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("-----Around Start-----");Object ret = pjp.proceed();System.out.println("-----Around End-----");return ret;} } public class AfterAdvice implements MethodAfterAdvice {@Overridepublic void after() throws Throwable {System.out.println("-----after-----");} }
1.2.3 MethodInvocation
上一节提到了MethodInvocaiton
,它是继承Joinpoint的一个子接口。Joinpoint是连接点,可以看作目标对象的全部方法。
它提供了四个方法:
- getThis获取
Joinpoint
代表方法所属对象; - getArgs获取
Joinpoint
代表方法的参数; - getMethod获取所代表的方法;
- proceed执行所代表的方法。
MethodInvocation
的含义是:方法调用,它的实现类ReflectiveMethodInvocation
,是AOP的核心,用来完成通知的调用(通知也是方法)。
具体来说proceed
内部会实现依据通知链顺序完成对每一个通知的调用,通知的具体执行交给下一节的MethodInterceptor
实现。
如1.2.1
图,MethodInvocation的proceed方法完成的是,通知类的拿取过程,如绿蓝红色线过程。
MethodInterceptor完成的是下部分的执行过程。两者是交错进行的相互调用。
1.2.4 MethodInterceptor
拦截器,表示对执行目标方法的流程进行拦截后,做一些自己的事情,然后再放回去执行正常流程。
它的invoke
和MethodInvocation
的proceed
方法是交替执行的,相互调用,这一点从下面的代码中也能看出。
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {private MethodBeforeAdvice advice;public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {this.advice=advice;}@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {advice.before();// invocation.proceed() 这个方法表示继续调用通知链中的下一个return invocation.proceed();}
}
public class MethodAroundAdviceInterceptor implements MethodInterceptor, Serializable {private MethodAroundAdvice advice;public MethodAroundAdviceInterceptor(MethodAroundAdvice advice) {this.advice = advice;}@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {return advice.around(new ProceedingJoinPoint(invocation));}
}public class MethodAfterAdviceInterceptor implements MethodInterceptor, Serializable {private MethodAfterAdvice advice;public MethodAfterAdviceInterceptor(MethodAfterAdvice advice) {this.advice=advice;}@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {advice.after();// invocation.proceed() 这个方法表示继续调用通知链中的下一个return invocation.proceed();}
}
1.2.5 MethodAdviceAdapter
方法装饰器。作用就是将通知转为对应的拦截器,拦截器内部包含通知,拦截下来后,执行通知。
public class MethodAdviceAdapter implements AdvisorAdapter {@Overridepublic MethodInterceptor getInterceptor(Advisor advisor) {Advice advice = advisor.getAdivce();if(advice instanceof MethodBeforeAdvice){return new MethodBeforeAdviceInterceptor((MethodBeforeAdvice)advice);} else if (advice instanceof MethodAroundAdvice) {return new MethodAroundAdviceInterceptor((MethodAroundAdvice)advice);}else{return new MethodAfterAdviceInterceptor((MethodAfterAdvice)advice);}}
}
1.2.6 ProceedingJoinPoint
它的作用其实就是对MethodInvocation
对象进行封装,完成对环绕通知的调用。这里不封装也可以,直接向环绕通知传递MethodInvocation
。
public class ProceedingJoinPoint {private MethodInvocation invocation;public ProceedingJoinPoint(MethodInvocation invocation) {this.invocation = invocation;}public Object proceed() throws Throwable {return invocation.proceed();}
}