美文网首页
JFinal 源码解析-AOP部分

JFinal 源码解析-AOP部分

作者: powerjiajun | 来源:发表于2019-01-28 10:55 被阅读0次

    一直比较欣赏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,很厉害。

    相关文章

      网友评论

          本文标题:JFinal 源码解析-AOP部分

          本文链接:https://www.haomeiwen.com/subject/ashijqtx.html