1. 职责链模式(Chain Of Responsibility Design Pattern)
在职责链模式中,多个处理器(也就是刚刚定义中说的“接收对象”)依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。
IHandler是所有处理器类的接口,handle()方法是抽象方法,每个具体的处理器类(HandlerA、HandlerB)的handle()方法用来处理请求,HandlerChain是处理器链,代码如下所示:
public interface IHandler {
boolean handle();
}
public class HandlerA implements IHandler {
@Override
public boolean handle() {
boolean handled = false;
//...
return handled;
}
}
public class HandlerB implements IHandler {
@Override
public boolean handle() {
boolean handled = false;
//...
return handled;
}
}
public class HandlerChain {
private List<IHandler> handlers = new ArrayList<>();
public void addHandler(IHandler handler) {
this.handlers.add(handler);
}
public void handle() {
for (IHandler handler : handlers) {
boolean handled = handler.handle();
if (handled) {
break;
}
}
}
}
// 使用举例
public class Application {
public static void main(String[] args) {
HandlerChain chain = new HandlerChain();
chain.addHandler(new HandlerA());
chain.addHandler(new HandlerB());
chain.handle();
}
}
2. Spring AOP的基本使用和源码解析
Spring AOP的基本使用请参考:SpringAOP
Spring AOP源码解析请参考:Spring AOP源码浅析
3.Spring AOP的职责链模式
3.1. MethodInteceptor接口
相当于上文中的IHandler,每个处理器都要实现该接口,其中invoke()方法,是处理器的处理逻辑
public interface MethodInteceptor {
Object invoke(MethodInvocation mi) throws Throwable;
}
3.2. CglibMethodInvocation
CglibMethodInvocation相当于上文中的HandlerChain ,该类中定义了拦截器链以及拦截器链的执行逻辑,代码模拟了Spring AOP的处理
public class CglibMethodInvocation implements MethodInvocation{
List<MethodInteceptor> inteceptors;
//当前拦截器链执行的位置。
int currentInterceptorIndex = -1;
//要切入的目标类对象,方法,方法参数
Object target;
Method method;
Object[] args;
CglibMethodInvocation(List<MethodInteceptor> inteceptors, Object target, Method method,Object[] args){
this.inteceptors = inteceptors;
this.target = target;
this.method = method;
this.args = args;
}
@Override
public Object proceed() throws Throwable {
//当拦截器链执行完之后,就执行目标类的目标方法。
if (this.currentInterceptorIndex == this.inteceptors.size() - 1) {
return method.invoke(target,args);
}
MethodInteceptor inteceptor = this.inteceptors.get(++currentInterceptorIndex);
return inteceptor.invoke(this);
}
}
3.3. MethodInvocation
MethodInvocation是CglibMethodInvocation的抽象。
public interface MethodInvocation {
Object proceed() throws Throwable;
}
3.4. MethodInteceptor的实现类
MethodInteceptor的实现类就是拦截器的具体实现,在每个invoke(MethodInvocation mi)方法中,都会调用mi.proceed()方法,让拦截器链能够继续往下执行。
public class MethodBeforeAdviceInterceptor implements MethodInteceptor{
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("假装这里执行了切面类@Before标注的方法。。。。。。。");
return mi.proceed();
}
}
public class AspectJAfterAdvice implements MethodInteceptor{
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try{
return mi.proceed();
}
finally {
System.out.println("假装这里执行了切面类@After标注的方法。。。。。。");
}
}
}
public class AfterReturningAdviceInterceptor implements MethodInteceptor{
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object returnVal = mi.proceed();
System.out.println("假装这里执行了切面类@AfterReturning标注的方法。。。。。。");
return returnVal;
}
}
public class AspectJAfterThrowingAdvice implements MethodInteceptor{
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try{
return mi.proceed();
}catch (Throwable throwable){
System.out.println("假装执行了切面类@AfterThrowing标注的方法");
throw throwable;
}
}
}
3.5. TargetClass目标类
TargetClass目标类就是简单模拟一下,Spring AOP中要被切入的类。
public class TargetClass {
public void targetMethod(String s){
//先简单抛个异常
//int i = 1 / 0;
System.out.println("假装这里执行了目标类的目标方法,传参:"+s);
}
}
3.6. 测试类MainClass
public class MainClass {
public static void main(String[] args) throws Throwable {
//初始化拦截器
List<MethodInteceptor> inteceptors = new ArrayList<>(4);
inteceptors.add(new AspectJAfterThrowingAdvice());
inteceptors.add(new AfterReturningAdviceInterceptor());
inteceptors.add(new AspectJAfterAdvice());
inteceptors.add(new MethodBeforeAdviceInterceptor());
//利用反射获取目标类以及目标方法,然后初始化参数
TargetClass targetClass = new TargetClass();
Method method = targetClass.getClass().getMethod("targetMethod",String.class);
Object[] methodArgs = {"我是参数"};
//执行职责链
CglibMethodInvocation methodInvocation = new CglibMethodInvocation(inteceptors,targetClass,method,methodArgs);
methodInvocation.proceed();
}
}
3.7. 测试结果
先注掉TargetClass中的int i = 1 / 0:
假装这里执行了切面类@Before标注的方法。。。。。。。
假装这里执行了目标类的目标方法,传参:我是参数
假装这里执行了切面类@After标注的方法。。。。。。
假装这里执行了切面类@AfterReturning标注的方法。。。。。。
Process finished with exit code 0
放开注释,让目标方法抛个异常:
假装这里执行了切面类@Before标注的方法。。。。。。。
假装这里执行了切面类@After标注的方法。。。。。。
假装执行了切面类@AfterThrowing标注的方法
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.ljessie.designpattern.behavior.chain.CglibMethodInvocation.proceed(CglibMethodInvocation.java:25)
at com.ljessie.designpattern.behavior.chain.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:7)
at com.ljessie.designpattern.behavior.chain.CglibMethodInvocation.proceed(CglibMethodInvocation.java:30)
at com.ljessie.designpattern.behavior.chain.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:7)
at com.ljessie.designpattern.behavior.chain.CglibMethodInvocation.proceed(CglibMethodInvocation.java:30)
at com.ljessie.designpattern.behavior.chain.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:6)
at com.ljessie.designpattern.behavior.chain.CglibMethodInvocation.proceed(CglibMethodInvocation.java:30)
at com.ljessie.designpattern.behavior.chain.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:7)
at com.ljessie.designpattern.behavior.chain.CglibMethodInvocation.proceed(CglibMethodInvocation.java:30)
at com.ljessie.designpattern.behavior.chain.MainClass.main(MainClass.java:23)
Caused by: java.lang.ArithmeticException: / by zero
at com.ljessie.designpattern.behavior.chain.TargetClass.targetMethod(TargetClass.java:9)
... 14 more
Process finished with exit code 1
到这里,拦截器链的执行逻辑与Spring AOP基本相符。在目标方法没有抛出异常时,会走AfterReturning方法;抛出异常时,会走AfterThrowing方法。
4. 总结
本文从Spring AOP的源码中,抽取出来职责链模式相关代码,简单介绍了下Spring AOP中职责链模式的应用。
在Spring AOP中,MethodInterceptor是所有拦截器的抽象接口,然后各个拦截器实现了MethodInterceptor接口。
CglibMethodInvocation是中的proceed()方法,定义了拦截器链的处理逻辑,当所有拦截器都执行完毕之后,开始执行目标类的目标方法。MethodInvocation接口是CglibMethodInvocation的抽象。
如有分析不当之处,还烦请各位看官多多指正。
网友评论