Spring AOP 与 AspectJ

简介: 前言Spring AOP 主要具有三种使用方式,分别是注解、XML 配置、API,目前在 Spring 中,由于 XML 需要大量配置,注解已经逐步取代 XML 配置,而 API 需要对 Spring 底层具有较深入的了解才能使用,因此注解成了应用 Spring 的首选方式。

前言


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。


目录
相关文章
|
4天前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
1月前
|
Java Spring
在Spring Boot中使用AOP实现日志切面
在Spring Boot中使用AOP实现日志切面
|
4天前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
|
7天前
|
安全 Java 开发者
Java 新手入门:Spring 两大利器IoC 和 AOP,小白也能轻松理解!
Java 新手入门:Spring 两大利器IoC 和 AOP,小白也能轻松理解!
14 1
|
6天前
|
Java Spring
Spring的AOP组件详解
该文章主要介绍了Spring AOP(面向切面编程)组件的实现原理,包括Spring AOP的基础概念、动态代理模式、AOP组件的实现以及Spring选择JDK动态代理或CGLIB动态代理的依据。
Spring的AOP组件详解
|
19天前
|
Java API Spring
Spring Boot 中的 AOP 处理
对 Spring Boot 中的切面 AOP 做了详细的讲解,主要介绍了 Spring Boot 中 AOP 的引入,常用注解的使用,参数的使用,以及常用 api 的介绍。AOP 在实际项目中很有用,对切面方法执行前后都可以根据具体的业务,做相应的预处理或者增强处理,同时也可以用作异常捕获处理,可以根据具体业务场景,合理去使用 AOP。
|
27天前
|
Java Spring 容器
Spring问题之Spring AOP是如何实现面向切面编程的
Spring问题之Spring AOP是如何实现面向切面编程的
|
24天前
|
缓存 安全 Java
Spring高手之路21——深入剖析Spring AOP代理对象的创建
本文详细介绍了Spring AOP代理对象的创建过程,分为三个核心步骤:判断是否增强、匹配增强器和创建代理对象。通过源码分析和时序图展示,深入剖析了Spring AOP的工作原理,帮助读者全面理解Spring AOP代理对象的生成机制及其实现细节。
17 0
Spring高手之路21——深入剖析Spring AOP代理对象的创建
|
4天前
|
XML Java 数据库
Spring5入门到实战------10、操作术语解释--Aspectj注解开发实例。AOP切面编程的实际应用
这篇文章是Spring5框架的实战教程,详细解释了AOP的关键术语,包括连接点、切入点、通知、切面,并展示了如何使用AspectJ注解来开发AOP实例,包括切入点表达式的编写、增强方法的配置、代理对象的创建和优先级设置,以及如何通过注解方式实现完全的AOP配置。
|
1月前
|
Java Spring
在Spring Boot中使用AOP实现日志切面
在Spring Boot中使用AOP实现日志切面