一直比较欣赏jfinal aop对于aop的责任链模式轻量实现,对其实现原理比较好奇,趁着最近手头工作告一段落便来阅读一下jfinal源码,作者波总关于aop的解读镇楼。
先来看看jfinal aop的使用方法,我们对一个Service进行增强的代码如下:
NoticeService service = Duang.duang(NoticeService.class);
接下来顺藤摸瓜,沿着这条线索走下去看看jfinal做了什么:
首先Duang这个类只是一个空壳子,依赖Enhancer类进而使用cglib来实现增强
public static <T> T duang(Class<T> targetClass) {
return (T)Enhancer.enhance(targetClass);
}
public static <T> T enhance(Class<T> targetClass) {
return (T)net.sf.cglib.proxy.Enhancer.create(targetClass, new Callback());
}
此处可以看到Callback是cglib的拦截器实现,用于对被增强类进行代理,我们可以在自定义的MethodInterceptor实现类的intercept方法里,对调用业务代码前后做一些事情
/**
* Callback.
*/
class Callback implements MethodInterceptor {
核心代码intercept:
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (excludedMethodName.contains(method.getName())) {
// if (method.getName().equals("finalize"))
// return methodProxy.invokeSuper(target, args);
// return this.injectTarget != null ? methodProxy.invoke(this.injectTarget, args) : methodProxy.invokeSuper(target, args);
// 保留上面注释部分,此处为优化
if (this.injectTarget == null || method.getName().equals("finalize")) {
return methodProxy.invokeSuper(target, args);
} else {
return methodProxy.invoke(this.injectTarget, args);
}
}
if (this.injectTarget != null) {
target = this.injectTarget;
Interceptor[] finalInters = interMan.buildServiceMethodInterceptor(injectInters, target.getClass(), method);
Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
invocation.useInjectTarget = true;
invocation.invoke();
return invocation.getReturnValue();
}
else {
Class<?> targetClass = target.getClass();
if (targetClass.getName().indexOf("$$EnhancerByCGLIB") != -1) {
targetClass = targetClass.getSuperclass();
}
Interceptor[] finalInters = interMan.buildServiceMethodInterceptor(injectInters, targetClass, method);
Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
invocation.useInjectTarget = false;
invocation.invoke();
return invocation.getReturnValue();
}
}
这个intercept方法其实就做了一件事情:组装Invocation对象并调用invoke方法返回执行结果。
Interceptor[] finalInters = interMan.buildServiceMethodInterceptor(injectInters, targetClass, method);
Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
invocation.useInjectTarget = false;
invocation.invoke();
return invocation.getReturnValue();
通常我们使用cglib实现动态代理时,需要实现的before和after操作都是在这个interceptor里面直接或间接实现,例如下面这段逻辑:
而jfinal为了实现aop操作面向业务开发人员的可配置和可扩展,将这部分放到业务人员编写的jfinal Interceptor接口实现类实现,在Invocation.invoke方法里去递归执行业务代码编写人员写好的所有拦截器,当递归结束后,最后执行被代理的业务方法。
Invocation.invoke方法源码:
public void invoke() {
if (index < inters.length) {
inters[index++].intercept(this);
}
else if (index++ == inters.length) { // index++ ensure invoke action only one time
try {
// Invoke the action
if (action != null) {
returnValue = action.getMethod().invoke(target, args);
}
// Invoke the method
else {
// if (!Modifier.isAbstract(method.getModifiers()))
// returnValue = methodProxy.invokeSuper(target, args);
if (useInjectTarget)
returnValue = methodProxy.invoke(target, args);
else
returnValue = methodProxy.invokeSuper(target, args);
}
}
catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
throw t instanceof RuntimeException ? (RuntimeException)t : new RuntimeException(e);
}
catch (RuntimeException e) {
throw e;
}
catch (Throwable t) {
throw new RuntimeException(t);
}
}
}
此处可以看到有这样一段逻辑控制代码:
public void invoke() {
if (index < inters.length) {
inters[index++].intercept(this);
}
else if (index++ == inters.length) {
调用被代理业务方法......
}
和我们编写的业务Interceptor中的一段代码遥相呼应,下图是框架使用人员编写的一个业务拦截器:
public class APIExceptionInterceptor implements Interceptor
{
private static Logger logger = LoggerFactory.getLogger(APIExceptionInterceptor.class);
@Override
public void intercept(Invocation inv)
{
Controller controller = inv.getController();
try {
inv.invoke();
} catch (Exception e) {
logger.error("================={}.{}接口调用异常,参数{},异常信息:", controller.getClass().getName(), inv.getMethodName(), JsonKit.toJson(controller.getParaMap()), e);
controller.renderJson(ResponseMapUtil.getFailedResponseMap(ErrorConstants.SERVER_API_ERR));
}
}
}
我们重点关注这行代码:
inv.invoke();
当执行第一个拦截器时,会调用invoke,然后继续回到Invocation.invoke函数的执行过程:
public void invoke() {
if (index < inters.length) {
inters[index++].intercept(this);
}
else if (index++ == inters.length) {
调用被代理业务方法......
}
此时的index已经递增到了1,所以又继续执行第二个拦截器,就这样互相回调,形成了一个递归,直到执行完所有的拦截器,递归才会结束。
执行完所有拦截器后,开始调用被代理的业务方法,拿到执行结果并返回,就执行完了一次aop操作,以下是Invocation.invoke中【调用被代理业务方法...】的源码:
try {
// Invoke the action
if (action != null) {
returnValue = action.getMethod().invoke(target, args);
}
// Invoke the method
else {
// if (!Modifier.isAbstract(method.getModifiers()))
// returnValue = methodProxy.invokeSuper(target, args);
if (useInjectTarget)
returnValue = methodProxy.invoke(target, args);
else
returnValue = methodProxy.invokeSuper(target, args);
}
}
catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
throw t instanceof RuntimeException ? (RuntimeException)t : new RuntimeException(e);
}
catch (RuntimeException e) {
throw e;
}
catch (Throwable t) {
throw new RuntimeException(t);
}
声明式事务、日志处理等操作都能够支持,后面的拦截器执行过程将会被前面执行的拦截器所包裹,类似于装饰器模式的装饰。
JFinal只是用了一系列拦截器加上一个递归调用操作,就实现了极简aop,很厉害。