Spring AOP 与 AspectJ

前言

Spring AOP 主要具有三种使用方式,分别是注解、XML 配置、API,目前在 Spring 中,由于 XML 需要大量配置,注解已经逐步取代 XML 配置,而 API 需要对 Spring 底层具有较深入的了解才能使用,因此注解成了应用 Spring 的首选方式。在 Spring AOP 中,Spring 又使用了 AspectJ 的注解,既然 Spring 单独提出一个 AOP 模块,那它为什么自己不提供一套注解?Spring AOP 和 AspectJ 又有何不同呢?本篇将尝试对这两者的区别与联系进行解释说明。

AspectJ 入门

既然 Spring AOP 使用到了 AspectJ 的注解,那么就有必要对 AspectJ 做一个初步的认识。

首先 AspectJ 是对 AOP 实现的框架,如果你对 AOP 的基础概念不太熟悉,可以参阅《从代理到 AOP,如何实现一个 AOP 框架?》。AspectJ 提供了独有的语法,通过自己的编译器对语法进行分析,然后将相关逻辑织入到目标类的字节码中。

1. 依赖引入

在 maven 项目中,可以引入 aspectj-maven-plugin 插件,这个插件会在编译时使用 AspectJ 的编译器。

		<plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.11</version>
                <dependencies>
                    <!-- 升级 AspectJ -->
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>1.9.6</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <!-- 打印编织信息 -->
                    <showWeaveInfo>true</showWeaveInfo>
                    <!-- 配置 JDK 版本号 -->
                    <source>1.8</source>
                    <target>1.8</target>
                    <complianceLevel>1.8</complianceLevel>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <!-- 使用这个目标来编织所有的主类 -->
                            <goal>compile</goal>
                            <!-- 使用这个目标来编织所有的测试类 -->
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

AspectJ 编译器会在生成的字节码中加上 AspectJ 自身的注解及相关类,因此还需要引入 aspectjrt 依赖。

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.6</version>
        </dependency>

2. AspectJ 示例

同样以日志打印为例,我们希望打印出目标方法的执行参数及返回内容。

public interface IService {
    String doSomething(String param);
}

public class ServiceImpl implements IService {

    @Override
    public String doSomething(String param) {
        return "param is : " + param;
    }
}

AspectJ 同时支持 .aj 文件和在 Java 类中使用注解,注解的使用方式与在 Spring AOP 中相同,我们创建一个 ServiceAspect.aj 文件,内容如下。

public aspect ServiceAspect {

    private Logger logger = LoggerFactory.getLogger(getClass());

    pointcut executionPointcut():execution(String IService.doSomething(String));

    before():executionPointcut(){
        logger.info("before:param is:{}", thisJoinPoint.getArgs());
    }

    after() returning(String result):executionPointcut(){
        logger.info("after returning:result is:{}", result);
    }

}

这里定义了一个 Aspect,和 Java 类相似,这里的关键字是 aspect,AspectJ 编译器会将这个文件编译为一个同名的类。

同时声明了一个名为 executionPointcut 的 Pointcut,以便 advice 复用,executionPointcut 拦截 IService.doSomething 方法的执行。

我们还在 Aspect 中定义了两个 Advice,这两个 Advice 指定了上述定义的 Pointcut,它们会在目标方法执行前后执行,然后分别打印目标方法的参数和返回值。

编写一个测试类。

public class App {

    public static void main(String[] args) {
        IService service = new ServiceImpl();
        service.doSomething("hello,aspectj");
    }
}

代码执行如下。

17:43:58.493 [main] INFO com.zzuhkp.blog.aspectj.ServiceAspect - before:param is:hello,aspectj
17:43:58.506 [main] INFO com.zzuhkp.blog.aspectj.ServiceAspect - after returning:result is:param is : hello,aspectj

成功拦截到目标方法的执行。

Spring AOP 设计目标

除了方法执行时拦截,AspectJ 还可以对字段、构造器等 Joint Point 进行拦截,作为一个专业的 AOP 框架来说功能更为强大。Spring 为什么又提出一个 AOP 框架呢?下面看下 Spring AOP 的设计目标。

Spring AOP 与大多数其他 AOP 框架有所不同,它并没有提供最完整的 AOP 实现。Spring AOP 的目标是提供 AOP 和 IOC 之间的紧密继承,以帮助解决应用程序中的常见问题。Spring 中的 Aspect 是使用普通的 bean 语法配置的,这是它和其他 AOP 实现的关键区别。Spring AOP 能解决大多数问题,对于 Spring AOP 不能解决的问题,使用 AspectJ 是最佳的选择。

Spring AOP 认为 AspectJ 是一个优秀的框架,它不与 AspectJ 竞争以提供全面的 AOP 解决方案,而是和 AspectJ 互补。Spring 将 Spring AOP 和 IOC 与 AspectJ 无缝集成,如果用户不喜欢使用 AspectJ 的注解,还可以通过 XML 配置来使用 Spring AOP。

Spring AOP 与 AspectJ 有何异同

根据前面的部分大致对这两者的不同做一个总结。

  • AspectJ 是一个完整的 AOP 实现,依赖特定的编译器和语法,在编译期织入字节码来实现 AOP。
  • Spring AOP 非完整 AOP 实现,Spring AOP 目的是为了和 IOC 容器整合,仅可选的提供了对 AspectJ 注解的支持,通过运行时创建目标类的代理来实现 AOP。
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大鹏cool

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值