JFinal 源码解析-AOP部分

2019-01-28  本文已影响0人  powerjiajun

一直比较欣赏jfinal aop对于aop的责任链模式轻量实现,对其实现原理比较好奇,趁着最近手头工作告一段落便来阅读一下jfinal源码,作者波总关于aop的解读镇楼。

image

先来看看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里面直接或间接实现,例如下面这段逻辑:


image.png

而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,很厉害。

上一篇下一篇

猜你喜欢

热点阅读