Spring 面向切面(AOP)
Spring 支持面向切面编程。
一、面向切面(AOP)
二、Spring 对 AOP 的支持
1. 名词解析
横切关注点:希望切面实现的功能
例如:日志记录、性能统计、安全检查、权限校验等
切面
例如:日志记录类、性能统计类、安全检查类、权限校验类等
增强:切面的具体工作
例如:日志记录类的打印日志方法、性能统计类的性能统计方法等
目标:被切入的对象
代理:被切入后的对象
连接点:目标可以被切入的位置
例如:数据库操作类实例的
add()
方法切入点:目标被切入的位置
2. 实现 AOP 的方式
- 实现增强接口
- 自定义类
- 注解
三、实现增强接口
1. 说明
增强接口自带了待实现的方法,并指定了该增强方法的切入时机。
2. 步骤
确保导入 aspectjweaver 依赖
1
2
3
4
5<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>版本号</version>
</dependency>在 Spring 配置文件中添加 aop 命名空间
1
2
3
4
5
6
7
8
9
10
11
12<?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
http://www.springframework.org/schema/aop/spring-aop.xsd">
···
</beans>编写增强接口的实现类,注册为 Bean
配置 aop
配置切入点
1
2
3
4
5<aop:config>
<aop:pointcut id="切入点名" expression="execution表达式"/>
</aop:config>配置增强
1
2
3
4
5<aop:config>
<aop:advisor advice-ref="非业务功能Bean名" pointcut-ref="切入点名"/>
</aop:config>
3. 切入点的配置
切入点通过 execution 表达式配置,具体如下:
1 |
|
修饰符(一般省略)
返回值类型(不能省略)
*
表示任意类型的返回值包名类名
方法名(不能省略)
- xxx:指定方法
xxx*
:指定前缀的方法*xxx
:指定后缀的方法*
:任意方法
参数
()
:无参(int, String)
:指定参数(..)
:任意参数
throws 异常(一般省略)
4. 增强接口
增强接口中定义了用于编写增强的方法
方法自带了参数,可以从中获取信息
方法、参数、业务功能类示例、返回结果、异常
不同的接口将会在不同的时机被执行
- MethodBeforeAdvice:在目标方法执行前会被执行
- AfterReturningAdvice:在目标方法执行后会被执行
- ThrowsAdvice:在目标方法抛出异常时会被执行
- MethodInterceptor:在目标方法执行前后会被执行
- IntroductionInterceptor:为目标对象添加新的属性和方法
1
2
3
4
5
6
7
8
public class 非义务功能类 implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
···做些什么···
}
}
5. 示例
UserService 接口:
1 |
|
UserService 接口实现类 UserServiceImpl:
1 |
|
增强接口实现类 Log:
1 |
|
applicationContext.xml:
1 |
|
测试代码:
1 |
|
运行结果:
四、自定义类
1. 说明
如果使用自定义类,需要在类中编写方法,在配置时指定该方法,并指定该方法的切入时机。
2. 步骤
确保导入 aspectjweaver 依赖
1
2
3
4
5<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>版本号</version>
</dependency>在 Spring 配置文件中添加 aop 命名空间
1
2
3
4
5
6
7
8
9
10
11
12<?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
http://www.springframework.org/schema/aop/spring-aop.xsd">
···
</beans>编写自定义类,注册为 Bean
在 Spring 配置文件中配置 aop
配置切入点
1
2
3
4
5<aop:config>
<aop:pointcut id="切入点名" expression="execution表达式"/>
</aop:config>配置切入
1
2
3
4
5
6
7
8
9<aop:config>
<aop:aspect ref="log">
<aop:时机 method="方法名" pointcut-ref="切入点名"/>
</aop:aspect>
</aop:config>
3. aop:时机
aop:before
:在目标方法执行前会被执行aop:after-returning
:在目标方法正常执行后会被执行aop:after-throwing
:在目标方法抛出异常后会被执行aop:after
:在目标方法执行后会被执行无论目标方法执行正常还是抛出异常
aop:around
:在目标方法执行前后会被执行aop:declare-parents
:为目标对象添加新的属性和方法
4. 示例
UserService 接口:
1 |
|
UserService 接口实现类 UserServiceImpl:
1 |
|
切面类 Log:
1 |
|
applicationContext.xml:
1 |
|
测试代码:
1 |
|
运行结果:
五、注解
1. 步骤
确保导入 aspectjweaver 依赖
1
2
3
4
5<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>版本号</version>
</dependency>在 Spring 配置文件中添加 aop 命名空间
1
2
3
4
5
6
7
8
9
10
11
12<?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
http://www.springframework.org/schema/aop/spring-aop.xsd">
···
</beans>在 Spring 配置文件中开启 @AspectJ 支持
1
2
3
4
5
6
7
8
9
10
11
12<?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
http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy/>
</beans>编写切面类
通过注解配置 aop
通过
@Aspect
,将切面类标记为切面:1
2
3
4
5
6@Aspect
public class 类名{
···
}通过
@时机(execution表达式)
,将方法标记为增强
2. @时机(execution表达式)
@Before(“execution表达式”):在目标方法执行前会被执行
@AfterReturning(“execution表达式”):在目标方法正常执行后会被执行
@AfterThrowing(“execution表达式”):在目标方法抛出异常后会被执行
@After(“execution表达式”):在目标方法执行后会被执行
无论目标方法执行正常还是抛出异常
@Around(“execution表达式”):在目标方法执行前后会被执行
3. 示例
UserService 接口:
1 |
|
UserService 接口实现类 UserServiceImpl:
1 |
|
切面类 Log:
1 |
|
applicationContext.xml:
1 |
|
测试代码:
1 |
|
运行结果: