持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
相关链接:Spring AOP 扫盲(概念篇)
概述
Spring 提供了两种方式来开配置 AOP 切面,一种是注解的方式,一种是 XML 配置文件的方式。现在已经很少使用 XML 配置文件来开发 Spring 应用了,因此,通过注解来配置 AOP 切面是比较推荐和常用的方式。
下面分别介绍如何通过这两种方式来配置 AOP 切面。
假设要多一下的 UserService 类型的add方法进行增强。
public class UserService {
public void add() {
System.out.println("Add...");
}
}
基于注解的 Spring AOP 切面配置
基于注解配置切面非常简单,示例代码如下:
@Component
@Aspect
public class UserAspect {
/**
* 前置通知
*/
@Before("execution(* pseudocode.UserService.add(..))")
public void before() {
System.out.println("Before...");
}
/**
* 环绕通知
*/
@Around("execution(* pseudocode.UserService.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Around Before ...");
// 执行被增强的目标方法
proceedingJoinPoint.proceed();
System.out.println("Around After ...");
}
}
首先,在一个类上添加@Aspect注解,这个类就是一个切面的定义。
然后,可以在这个类中定义一些方法作为增强的逻辑,比如以上的代码中,分别定义了前置增强和环绕增强,其它几个增强类型的定义与前置增强类似,只不过用到的注解不同,分别是@After、@AfterThrowing和@AfterReturning,为了避免代码过长,就不一一罗列了。在这几个类型增强注解当中,配置的属性值就是切入点表达式。
如果几个增强方法用到了同样的切入点表达式,还可以单独配置切入点表达式,并在增强方法的注解中引用,像下面这样。
@Pointcut("execution(* pseudocode.UserService.add(..))")
public void point() {
}
/**
* 前置通知
*/
@Before("point()")
public void before() {
System.out.println("Before...");
}
注意,配置切入点表达式的方法,不会被执行。
配置完这些,我们就定义好了一个切面,要让它起作用,还需要告诉 Spring 开启 AOP 支持。
开启的方式有两种,第一种是针对基于 XML 配置的 Spring 上下文,可以在 XML 配置文件中开启,只需要在配置文件的根结点中添加如下的字节点即可。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy/>
</beans>
然后再把切面配置类注册为一个 Bean 就可以了。
另外一种就是针对基于注解配置的 Spring 上下文,可以通过在@Configuration配置类上添加@EnableAspectJAutoProxy注解来开启 Spring 对 AOP 特性的支持,此时,还需要给切面配置类添加@Component注解,使其作为一个 Bean 被注册到 Spring 容器中,配置类的实例如下:
@Configuration
@EnableAspectJAutoProxy
public class SpringConfig {
}
基于 XML 文件的 Spring AOP 切面配置
接下来介绍在 XML 配置文件中配置切面,这种方式只能用于基于 XML 配置的 Spring 上下文。
首先,还是要通过一个类和其中的方法定义切面的增强逻辑。
public class UserAspect {
/**
* 前置通知
*/
public void before() {
System.out.println("Before...");
}
/**
* 环绕通知
*/
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Around Before ...");
// 执行被增强的目标方法
proceedingJoinPoint.proceed();
System.out.println("Around After ...");
}
}
与通过注解配置切面不同,这个类只是一个普通的类,包含定义了增强逻辑的方法就可以了,然后是 XML 配置文件中对切面的配置。、
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="pseudocode.UserService"/>
<bean id="userAspect" class="pseudocode.UserAspect"/>
<aop:config>
<aop:pointcut id="pointcut"
expression="execution(* pseudocode.UserService.add(..))"/>
<aop:aspect ref="userAspect">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
XML 配置文件中的切面配置很容易理解,跟通过注解的方式很相似,只是换了一种配置格式而已。
另外,如果切面是通过 XML 配置文件配置的,那么 Spring 会自动开启对 AOP 特性的支持。
AspectJ 切面配置方式
在基于注解的切面配置中,使用到的@``Aspect等所有的注解,并非来自 Spring,而是来自另外一个 AOP 框架,即 AspectJ。Spring 在切面配置方面,使用了 AspectJ 的切入点表达式和配置方式,即使是通过 XML 来配置切面,也保持了同样的配置模型。
除此之外,在 Spring 应用运行时,对切入点的解析和匹配,也会使用 AspectJ 的库来完成。
但是,在运行方式上,Spring AOP 和 AspectJ 是完全不同的两个 AOP 框架。
总结
本文介绍了 Spring 中最基本的切面配置方法,以及开启 Spring 对 AOP 特性支持的方法,适合初学者阅读。最近在更新【Spring Framework 源码解读】专栏,这篇也是为了之后分析 AOP 相关的源码做准备。