JSRUN 用代码说话

AOP

传统 AOP 实现需要引入大量繁杂而多余的概念,例如:Aspect、Advice、Joinpoint、Poincut、 Introduction、Weaving、Around 等等,并且需要引入 IOC 容器并配合大量的 XML 或者 annotation 来进行组件装配。

传统 AOP 不但学习成本极高,开发效率极低,开发体验极差,而且还影响系统性能,尤 其是在开发阶段造成项目启动缓慢,极大影响开发效率。

JFinal 采用极速化的 AOP 设计,专注 AOP 最核心的目标,将概念减少到极致,仅有三个 概念:Interceptor、Before、Clear,并且无需引入 IOC 也无需使用繁杂的 XML。

拦截器

Interceptor 可以对方法进行拦截,并提供机会在方法的前后添加切面代码,实现 AOP 的 核心目标。Interceptor 接口仅仅定了一个方法 void intercept(Invocation inv)。以下是简单的示例:

public class DemoInterceptor implements Interceptor {
    public void intercept(Invocation inv) { System.out.println("Before method invoking"); inv.invoke();
    System.out.println("After method invoking");
    }
}

以上代码中的 DemoInterceptor 将拦截目标方法,并且在目标方法调用前后向控制台输出 文本。inv.invoke()这一行代码是对目标方法的调用,在这一行代码的前后插入切面代码可以很 方便地实现 AOP。

nvocation 作为 Interceptor 接口 intercept 方法中的唯一参数,提供了很多便利的方法在拦 截器中使用。以下为 Invocation 中的方法:

方法 描述
void invoke() 传递本次调用,调用剩下的拦截器与目标方法
Controller getController() 获取 Action 调用的 Controller 对象(仅用于控制层拦截)
String getActionKey() 获取 Action 调用的 action key 值(仅用于控制层拦截)
String getControllerKey() 获取 Action 调用的 controller key 值(仅用于控制层拦截)
String getViewPath() 获取 Action 调用的视图路径(仅用于控制层拦截)
<T> T getTarget() 获取被拦截方法所属的对象
Method getMethod() 获取被拦截方法的 Method 对象
String getMethodName() 获取被拦截方法的方法名
Object[] getArgs() 获取被拦截方法的所有参数值
Object getArg(int) 获取被拦截方法指定序号的参数值
<T> T getReturnValue() 获取被拦截方法的返回值
void setArg(int) 设置被拦截方法指定序号的参数值
void setReturnValue(Object) 设置被拦截方法的返回值
boolean isActionInvocation() 判断是否为 Action 调用,也即是否为控制层拦截

Before

Before 注解用来对拦截器进行配置,该注解可配置 Class、Method 级别的拦截器,以下是 代码示例:

// 配置一个class 级别的拦截器,它将拦截本类中的所有方法
@Before(AaaInter.class)
public class BlogController  extends Controller
{

  //配置多个Method 级别的拦截器,仅拦截本方法
  @Before(BbbInter.class,CccInter.class)
  public void  index(){
  }

  //未配置Method 级别拦截器,但会被class 级别拦截器AaaInter所拦截
  public void show(){
  }
}

如上代码所示,Before 可以将拦截器配置为 Class 级别与 Method 级别,前者将拦截本类 中所有方法,后者仅拦截本方法。此外 Before 可以同时配置多个拦截器,只需用在大括号内 用逗号将多个拦截器进行分隔即可。

除了 Class 与 Method 级别的拦截器以外,JFinal 还支持全局拦截器以及 Inject 拦截器(Inject

拦截将在后面介绍),全局拦截器分为控制层全局拦截器与业务层全局拦截器,前者拦截控制 层所有 Action 方法,后者拦截业务层所有方法。

全局拦截器需要在 YourJFinalConfig 进行配置,以下是配置示例:

public class AppConfig extends JFinalConfig {
    public void configInterceptor(Interceptors me) {
    // 添加控制层全局拦截器
    me.addGlobalActionInterceptor(new GlobalActionInterceptor());

    // 添加业务层全局拦截器
    me.addGlobalServiceInterceptor(new GlobalServiceInterceptor());

    // 为兼容老版本保留的方法,功能与addGlobalActionInterceptor完全一样
    me.add(new GlobalActionInterceptor());
    }
}

当某个 Method 被多个级别的拦截器所拦截,拦截器各级别执行的次序依次为:Global、 Inject、Class、Method,如果同级中有多个拦截器,那么同级中的执行次序是:配置在前面的 先执行。

Clear

拦截器从上到下依次分为 Global、Inject、Class、Method 四个层次,Clear 用于清除自身 所处层次以上层的拦截器。

Clear 声明在 Method 层时将针对 Global、Inject、Class 进行清除。Clear 声明在 Class 层时 将针对 Global、Inject 进行清除。Clear 注解携带参数时清除目标层中指定的拦截器。

Clear 用法记忆技巧:

  • 共有 Global、Inject、Class、Method 四层拦截器

  • 清除只针对 Clear 本身所处层的向上所有层,本层与下层不清除

  • 不带参数时清除所有拦截器,带参时清除参数指定的拦截器

在某些应用场景之下,需要移除 Global 或 Class 拦截器。例如某个后台管理系统,配置了 一个全局的权限拦截器,但是其登录 action 就必须清除掉她,否则无法完成登录操作,以下是 代码示例:

// login方法需要移除该权限拦截器才能正常登录
@Before(AuthInterceptor.class)
public class UserController extends Controller {
    // AuthInterceptor 已被Clear清除掉,不会被其拦截
    @Clear
    public void login() {
    }

    // 此方法将被AuthInterceptor拦截
    public void show() {
    }
}

Clear 注解带有参数时,能清除指定的拦截器,以下是一个更加全面的示例:

@Before(AAA.class)
public class UserController extends Controller {
    @Clear
    @Before(BBB.class)
    public void login() {
    // Global、Class级别的拦截器将被清除,但本方法上声明的BBB不受影响
    }

    @Clear({AAA.class, CCC.class})// 清除指定的拦截器AAA与CCC
    @Before(CCC.class)
    public void show() {
    // 虽然Clear注解中指定清除CCC,但她无法被清除,因为清除操作只针对于本层以上的各层
    }
}

Interceptor 的触发

JFinal 中的 AOP 被划分为控制层 AOP 以及业务层 AOP,严格来说业务层 AOP 并非仅限 于在业务层使用,因为 JFinal AOP 可以应用于其它任何地方。

控制层拦截器的触发,只需发起 action 请求即可。业务层拦截器的触发需要先使用 enhance方法对目标对象进行增强,然后调用目标方法即可。以下是业务层 AOP 使用的例子:


// 定义需要使用AOP的业务层类
public class OrderService {
    // 配置事务拦截器
    @Before(Tx.class)
    public void payment(int orderId, int userId) {
    // service code here
    }
}

// 定义控制器,控制器提供了enhance系列方法可对目标进行AOP增强
public class OrderController extends Controller {
    public void payment() {
    // 使用 enhance方法对业务层进行增强,使其具有AOP能力 OrderService service = enhance(OrderService.class);

    // 调用payment方法时将会触发拦截器
    service.payment(getParaToInt("orderId"), getParaToInt("userId"));
    }
}

以上代码中 OrderService 是业务层类,其中的 payment 方法之上配置了 Tx 事务拦截器, OrderController 是控制器,在其中使用了 enhance 方法对 OrderSevice 进行了增强,随后调用其 payment 方法便可触发 Tx 拦截器。简言之,业务层 AOP 的触发相对于控制层仅需多调用一次 enhance 方法即可,而 Interceptor、Before、Clear 的使用方法完全一样。

Duang、Enhancer

Duang、Enhancer 用来对目标进行增强,让其拥有 AOP 的能力。以下是代码示例:

public class TestMain{
    public void main(String[] args) {
    // 使用Duang.duang方法在任何地方对目标进行增强
    OrderService service = Duang.duang(OrderService.class);
    // 调用payment方法时将会触发拦截器
    service.payment(…);

    // 使用Enhancer.enhance方法在任何地方对目标进行增强
    OrderService service = Enhancer.enhance(OrderService.class);
    }
}

Duang.duang()、Enhancer.enhance()与 Controller.enhance()系方法在功能上完全一样,她们 除了支持类增强以外,还支持对象增强,例如 duang(new OrderService())以对象为参数的用法, 功能本质上是一样的,在此不再赘述。

使用 Duang、Enhancer 类可以对任意目标在任何地方增强,所以 JFinal 的 AOP 可以应用 于非 web 项目,只需要引入 jfinal.jar 包,然后使用 Enhancer.enhance()或 Duang.duang()即可极 速使用 JFinal 的 AOP 功能。

Inject 拦截器

Inject 拦截器是指在使用 enhance 或 duang 方法增强时使用参数传入的拦截器。Inject 可以 对目标完全无侵入地应用 AOP。

假如需要增强的目标在 jar 包之中,无法使用 Before 注解对其配置拦截器,此时使用 Inject拦截器可以对 jar 包中的目标进行增强。如下是 Inject 拦截器示例:

public void injectDemo() {
    // 为enhance方法传入的拦截器称为Inject拦截器,下面代码中的Tx称为Inject拦截器 OrderService service = Enhancer.enhance(OrderService.class,         Tx.class); service.payment(…);
}

如上代码中 Enhance.enhance()方法的第二个参数 Tx.class 被称之为 Inject 拦截器,使用此方法便可完全无侵入地对目标进行 AOP 增强。

Inject 拦截器与前面谈到的 Global、Class、Method 级别拦截器是同一层次上的概念。与 Class 级拦截器一样,Inject 拦截器将拦截被增强目标中的所有方法。Inject 拦截器可以被认为 就是 Class 级拦截器,只不过执行次序在 Class 级拦截器之前而已。

JSRUN闪电教程系统是国内最先开创的教程维护系统, 所有工程师都可以参与共同维护的闪电教程,让知识的积累变得统一完整、自成体系。 大家可以一起参与进共编,让零散的知识点帮助更多的人。
X
支付宝
9.99
无法付款,请点击这里
金额: 0
备注:
转账时请填写正确的金额和备注信息,到账由人工处理,可能需要较长时间
如有疑问请联系QQ:565830900
正在生成二维码, 此过程可能需要15秒钟