一、非注解式简易版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 { @Override public void before() throws Throwable { System.out.println("-----before-----"); } } public class LogAdvice implements MethodAroundAdvice { @Override public 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 { @Override public 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;
}
@Override
public 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;
}
@Override
public 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;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
advice.after();
// invocation.proceed() 这个方法表示继续调用通知链中的下一个
return invocation.proceed();
}
}
1.2.5 MethodAdviceAdapter
方法装饰器。作用就是将通知转为对应的拦截器,拦截器内部包含通知,拦截下来后,执行通知。
public class MethodAdviceAdapter implements AdvisorAdapter {
@Override
public 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();
}
}