1 概述
传统 AOP 实现需要引入大量繁杂而多余的概念,例 如:Aspect、Advice、Joinpoint、Poincut、Introduction、Weaving、Around 等等,并且需要引入 IOC 容器并配合大量的 XML 或者 annotation来进行组件装配。
传统 AOP 不但学习成本极高,开发效率极低,开发体验极差,而且还影响系统性能,尤其是在开发阶段造成项目启动缓慢,极大影响开发效率。
JFinal 采用极速化的 AOP 设计,专注 AOP 最核心的目标,将概念减少到极致,仅有三个概念:Interceptor、Before、Clear,并且无需引入 IOC 也无需使用繁杂的 XML。
2 Interceptor
Interceptor 可以对方法进行拦截,并提供机会在方法的前后添加切面代码,实现 AOP 的核心目标。Interceptor 接口仅仅定了一个方法 void intercept(Invocation inv)。以下是简单的示例:
以上代码中的 DemoInterceptor 将拦截目标方法,并且在目标方法调用前后向控制台输出文本。inv.invoke()这一行代码是对目标方法的调用,在这一行代码的前后插入切面代码可以很方便地实现 AOP。
Invocation 作为 Interceptor 接口 intercept 方法中的唯一参数,提供了很多便利的方法在拦截器中使用。以下为 Invocation 中的方法:
3 Before
Before 注解用来对拦截器进行配置,该注解可配置 Class、Method 级别的拦截器,以下是代码示例:
如上代码所示,Before 可以将拦截器配置为 Class 级别与 Method 级别,前者将拦截本类中所有方法,后者仅拦截本方法。此外 Before 可以同时配置多个拦截器,只需用在大括号内用逗号将多个拦截器进行分隔即可。
除了Class与Method级别的拦截器以外,JFinal还支持全局拦截器以及Inject拦截器(Inject拦截将在后面介绍),全局拦截器分为控制层全局拦截器与业务层全局拦截器,前者拦截控制层所有 Action 方法,后者拦截业务层所有方法。
全局拦截器需要在 YourJFinalConfig 进行配置,以下是配置示例:
当某个 Method 被多个级别的拦截器所拦截,拦截器各级别执行的次序依次为:Global、Class、Inject、Method,如果同级中有多个拦截器,那么同级中的执行次序是:配置在前面的先执行。
4 Clear
Clear 注解用于清除声明在 Method 以外的拦截器,也即只能清除 Global、Class 或 Inject拦截器。
Clear 用法记忆技巧:
不带参数时清除所有拦截器
带上参数时只清除该参数指定的拦截器
清除操作仅作用于 Method 之外声明的拦截器
在某些应用场景之下,需要移除 Global 或 Class 拦截器。例如某个后台管理系统,配置了一个全局的权限拦截器,但是其登录 action 就必须清除掉她,否则无法完成登录操作,以下是代码示例:
Clear 注解带有参数时,能清除指定的拦截器,以下是一个更加全面的示例:
JFinal 2.0 对于 Clear 功能进行了改进,如果不需对旧项目升级,不必理会她们之间的异同,只需知道更加简便的 Clear 用法即可。老版本的类名为 ClearInterceptor,如果需要对老系统升级可了解一下她们的异同如下:
ClearInterceptor 行为有层次概念,共 Global、Class、Method 三层。层次之间有上下关系:Method 上层是 Class 层,Class 上层是 Global 层。而 Clear 无层次概念,它作用于所有非Method 之上的拦截器。
ClearInterceptor 清除只针于本层的上一层或上两层,不带参数或者使用 ClearLayer.UPPER时清除上一层,使用参数 ClearLayer.ALL 时清除上面两层,本层和下一层永远不受影响。而 Clear 无参时清除所有拦截器,有参时清除参数指定的拦截器。
ClearInterceptor 可以声明在 Class 之上,而 Clear 只能声明在 Method 之上,这样就使 Clear避开了上层下层等等这些概念以及与之相关的逻辑关系,极大降低了学习成本,极度易于使用。
5 Interceptor 的触发
JFinal 中的 AOP 被划分为控制层 AOP 以及业务层 AOP,严格来说业务层 AOP 并非仅限于在业务层使用,因为 JFinal AOP 可以应用于其它任何地方。 控制层拦截器的触发,只需发起 action 请求即可。业务层拦截器的触发需要先使用 enhance方法对目标对象进行增强,然后调用目标方法即可。以下是业务层 AOP 使用的例子:
以上代码中 OrderService 是业务层类,其中的 payment 方法之上配置了 Tx 事务拦截器,OrderController 是控制器,在其中使用了 enhance 方法对 OrderSevice 进行了增强,随后调用其payment 方法便可触发 Tx 拦截器。简言之,业务层 AOP 的触发相对于控制层仅需多调用一次enhance 方法即可,而 Interceptor、Before、Clear 的使用方法完全一样。
6 Enhancer
Enhancer 工具类用来对目标进行增强,让其拥有 AOP 的能力。以下是代码示例:
Enhancer.enhance()系列方法与 Controller.enhance()系方法在功能上完全一样,她们除了支持类增强以外,还支持对象增强,例如 enhance(new OrderService())以对象为参数的用法,功能本质上是一样的,在此不再赘述。
使用 Enhancer 类可以对任意目标在任何地方增强,所以 JFinal 的 AOP 可以应用于非 web项目,只需要引入 jfinal.jar 包,然后使用 Enhancer.enhance()即可极速使用 JFinal 的 AOP 功能。
7 Inject 拦截器
Inject 拦截器是指在使用 enhance 方法增强时使用参数传入的拦截器。Inject 可以对目标完全无侵入地应用 AOP。假如需要增强的目标在 jar 包之中,无法使用 Before 注解对其配置拦截器,此时使用 Inject拦截器可以对 jar 包中的目标进行增强。如下是 Inject 拦截器示例:
如上代码中 Enhance.enhance()方法的第二个参数 Tx.class 被称之为 Inject 拦截器,使用此方法便可完全无侵入地对目标进行 AOP 增强。
Inject 拦截器与前面谈到的 Global、Class、Method 级别拦截器是同一层次上的概念。与Class 级拦截器一样,Inject 拦截器将拦截被增强目标中的所有方法。Inject 拦截器可以被认为就是 Class 级拦截器,只不过执行次序在 Class 级拦截器之前而已。