美文网首页编程之路
Spring 中注入 AspectJ 切面

Spring 中注入 AspectJ 切面

作者: 皱巴巴 | 来源:发表于2018-10-26 11:05 被阅读3次

最近在阅读《Spring 实战》(第四版),跟着书中的讲解做一些练习。其中,在注入 Aspect 切面那一节卡了一会。主要是对 AspectJ 不了解,Gradle 的一些用法不熟悉导致,于是决定通过一篇博客记录一下。在后面的阅读过程中,如果遇到其他的问题,我也会写到博客中。

相关知识

Spring 提供了 4 中类型的 AOP 支持:

  • 基于代理的经典 Spring AOP;
  • 纯 POJO 切面;
  • @AspectJ 注解驱动的切面;
  • 注入式 AspectJ 切面。

前三种都是 Spring AOP 实现的变体,Spring AOP 构建在动态代理之上,通过在代理类中包裹切面,Spring 在运行期间把切面织入到 Spring 管理的 bean 中。因为直到应用需要被代理 bean 时,Spring 才创建对象,所以不需要特殊的编译器来织入 Spring AOP 切面,而正因为 Spring 基于动态代理,所以 Spring 只支持方法连接点。

织入

织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:

  • 编译期:切面在目标类编译时织入。这种方式需要特殊的编译器,例如 AspectJ 的 ajc。
  • 类加载期:切面在目标类加载到 JVM 时被织入。这种方式需要特殊的类加载器,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ 5 的加载时织入(load-time weaving,LTW) 就支持以这种方式织入切面。
  • 运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP 容器会为目标对象动态地创建一个代理对象。Spring AOP 就是以这种方式织入切面的。

注入 AspectJ 切面

正如上文介绍的 Spring AOP 基于动态代理实现,局限于方法拦截,而 AspectJ 提供了 Spring AOP 所不能支持的许多类型的切点。

AspectJ 切面与 Spring 是相互独立的。但是如果在执行通知时,切面依赖一个或多个类,我们可以借助 Spring 的依赖注入把 bean 装配紧 AspectJ 切面中。

根据书中的示例,编写一个表演和评论员的例子。

编写切面

使用 AspectJ 实现表演的评论员,创建 CriticAspect.aj 文件,注意这里使用 .aj 作为后缀

package concert;

public aspect CriticAspect {
    private CriticismEngine criticismEngine;

    pointcut performance():execution(* concert.Performance.perform(..));

    pointcut construct():execution(concert.CriticismEngineImpl.new());

    after():performance(){
        System.out.println(criticismEngine.getCriticism());
    }

    after():construct(){
        System.out.println("After Performance constructor");
    }


    before():construct(){
        System.out.println("Before Performance constructor");
    }

    public CriticismEngine getCriticismEngine() {
        return this.criticismEngine;
    }

    public void setCriticismEngine(CriticismEngine criticismEngine) {
        this.criticismEngine = criticismEngine;
    }
}

CriticAspect 的主要职责是在表演结束后为表演发表评论,但是不是自己发表评论,而是通过 CriticismEngine 来获取一个评论,这里就可以通过 Spring 注入。

实现 CriticismEngine 和 Performance

这里我就不贴出具体的实现了,主要就是定义两个接口,然后添加两个实现类。接口如下:

// Performance 接口
package concert;

public interface Performance {
    void perform();
}

// CriticismEngine 接口
package concert;

public interface CriticismEngine {
    String getCriticism();
}

具体代码见 Github

Spring 配置

这里需要注意的是 AspectJ 切面根本不需要 Spring 就可以织入到我们的应用中。但是如果想使用 Spring 依赖注入为 AspectJ 注入写作者,就需要配置。配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="performance" class="concert.Music" />

  <bean id="criticismEngine" class="concert.CriticismEngineImpl">
    <property name="criticismPool">
      <list>
        <value>Worst performance ever!</value>
        <value>I laughed, I cried, then I realized I was at the wrong show.</value>
        <value>A must see show!</value>
      </list>
    </property>
  </bean>

  <bean class="concert.CriticAspect" factory-method="aspectOf">
    <property name="criticismEngine" ref="criticismEngine" />
  </bean>
</beans>

主要配置了 CriticismEnginePerformance 的两个 bean(这就没什么好介绍的) 和 CriticAspect

其中 CriticAspect bean 的声明和其他的没什么区别,主要在于使用了 factory-method 属性。Spring 不负责创建 CriticAspect(由 AspectJ 创建),所以不能在 Spring 中简单地把 CriticAspect 声明为一个 bean,而需要一种方式为 Spring 提供已经由 AspectJ 创建的 CriticAspect 实例,从而可以注入 CriticismEngine。

幸好,所有的 AspectJ 切面都提供了一个静态的 aspectOf() 方法,可以返回切面的实例。所以为了获得切面的实例,需要使用 factory-method 来调用 aspectOf() 方法而不是调用 CriticAspect 的构造器方法。

编译

我使用 Gradle 作为构建工具,Gradle 提供了 aspectj.gradle 插件。相关配置如下:

buildscript {
    ext {
        aspectjVersion = "1.8.5"
    }
}

plugins {
    id "aspectj.gradle" version "0.1.6"
}

使用 aspectj.gradle 插件需要设置 aspectjVersion 属性。

总结

《Spring 实战》一书中的练习我都上传到了 Github,可以自行查阅。

这次主要的问题在于:

  1. 不知道 AspectJ 是什么,以为 AspectJ 特有的语言也是 java,创建 java 文件,编辑器一直不支持语法。
  2. Gradle 还不熟悉,使用插件折腾了半天。

相关文章

  • 【Spring实战】面向切面编程

    本章内容: 面向切面编程的基本原理 通过POJO创建切面 使用@AspectJ注解 为AspectJ切面注入依赖 ...

  • Spring 中注入 AspectJ 切面

    最近在阅读《Spring 实战》(第四版),跟着书中的讲解做一些练习。其中,在注入 Aspect 切面那一节卡了一...

  • Spring AOP使用注解创建切面

    Spring使用xml创建切面和使用AspectJ创建切面有所不同的。下面使用AspectJ来创建切面。 一、先举...

  • Spring Aop之注入AspectJ切面

    没有搞懂这是什么??所以写一个这章的总结吧! 用了大概一个星期的时间,才把Spring AOP的内容学完。其实Sp...

  • Spring切入点表达式常用写法

    自从使用AspectJ风格切面配置,使得Spring的切面配置大大简化,但是AspectJ是另外一个开源项目,其规...

  • AspectJ

    对于AspectJ,AspectJ的切入点和目标的切入方法不能是在同一个类中。如果是在同一个类中,那么切面切点注入...

  • 7.SpringAop之声明式Aop基于配置:AspectJAw

    介绍 AspectJ项目是对java语言面向切面编程的一个扩展,Spring框架实现了AspectJ的部分功能。A...

  • spring-4.3.4.RELEASE集成AOP 实战

    一、依赖引入 (包括 spring-aop 以及 aspectj) 二、切面配置代码 (使用 javaConfig...

  • Spring面向切面编程

    Spring提供了4种类型的AOP支持: 基于代理的经典Spring AOP; 纯POJO切面; @AspectJ...

  • AOP笔记

    Spring提供了4种类型的AOP支持: 基于代理的经典Spring AOP 纯POJO切面 @AspectJ注解...

网友评论

    本文标题:Spring 中注入 AspectJ 切面

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