# 4AOP通知
# 五种通知类型
注解 | 说明 |
---|---|
Before Advice | 前置通知,目标方法运行前执行 |
After Returning Advice | 返回后通知,目标方法返回数据后执行 |
After Throwing Advice | 异常通知,目标方法抛出异常后执行 |
After Advice | 后置通知,目标方法运行后执行 |
Around Advice | 环绕通知,最强大的通知,自定义通知执行时机,可决定目标方法是否运行 |
# 特殊的“通知”-引介增强
它本质是一个拦截器
- 引介增强(IntroductionInterceptor)是对类的增强,而非方法
- 引介增强运行在运行时为目标类增加新属性或方法(这是一种很高级的应用)
- 引介增强允许在运行时改变类的行为,让类随运行环境动态变更
引介增强使用是比较复杂的,在实际开发中使用也是比较少的,只需要了解一下即可
# before 后置通知
后置通知无法获取到目标方法运行过程中所产生的返回值或者是内部抛出的异常,如果需要获取返回值,则需要After Returning Advice(返回后通知),如果需要内部抛出的异常,则需要After Throwing Advice(异常通知)
public void doAfter(JoinPoint joinPoint){
System.out.println(this.getClass().getName() + ".doAfter();后置通知");
}
1
2
3
2
3
<!--后置通知无法获取到目标方法运行过程中所产生的返回值或者是内部抛出的异常,如果需要获取返回值,则需要After Returning Advice(返回后通知),如果需要内部抛出的异常,则需要After Throwing Advice(异常通知)-->
<aop:after method="doAfter" pointcut-ref="pointcut"></aop:after>
1
2
2
# After Returning 返回后通知
返回后通知用于接收目标方法所产生的返回值,它也是在目标方法执行完以后才产生的
public void doAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println(this.getClass().getName() + ".doAfterReturning();返回后通知,返回值为:"+ret);
}
1
2
3
2
3
<!--返回后通知,可以接收目标方法的返回值; returning="ret": 返回值由哪一个形参接收-->
<!--返回后通知与后置通知的执行顺序:是配置位置的顺序决定的-->
<aop:after-returning method="doAfterReturning" pointcut-ref="pointcut" returning="ret"></aop:after-returning>
1
2
3
2
3
# After Throwing 异常通知
public void doAfterThrowing(JoinPoint joinPoint,Throwable throwable){
System.out.println(this.getClass().getName() + ".doAfterThrowing();返回后异常通知,异常信息为:"+throwable.getMessage());
}
1
2
3
2
3
<!--异常通知-->
<aop:after-throwing method="doAfterThrowing" pointcut-ref="pointcut" throwing="throwable"></aop:after-throwing>
1
2
2
# 完整示例代码如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!--aspectjweaver是Spring AOP的底层依赖,也就是说Spring AOP只有引入aspectjweaver之后,才能正常的运行-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
package com.torey.spring.aop.aspect;
import org.aspectj.lang.JoinPoint;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.SimpleFormatter;
/**
* @Author http://torey611.gitee.io/li-tao-feng/
* @Email torey6061@qq.com
* @Date 2021/5/1 16:21
* @描述: 切面类
*/
public class MethodAspect {
/**
* 切面方法,用于扩展额外的功能
* @param joinPoint 连接点,通过连接点可以获取目标类/方法的信息
*/
public void printExecutionTime(JoinPoint joinPoint){
SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String nowDateStr = sdf.format(new Date());
//获取目标类的名称
String className= joinPoint.getTarget().getClass().getName();
//获取目标方法名称
String methoName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("---->"+nowDateStr+":"+className+"."+methoName);
if (args.length>0) {
System.out.println("====存在参数,参入如下====");
for (Object arg : args) {
System.out.println("参数类型为:"+ arg.getClass()+"参数值为:"+ arg);
}
}
}
public void doAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println(this.getClass().getName() + ".doAfterReturning();返回后通知,返回值为:"+ret);
}
public void doAfter(JoinPoint joinPoint){
System.out.println(this.getClass().getName() + ".doAfter();后置通知");
}
public void doAfterThrowing(JoinPoint joinPoint,Throwable throwable){
System.out.println(this.getClass().getName() + ".doAfterThrowing();返回后异常通知,异常信息为:"+throwable.getMessage());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.torey.spring.aop.dao;
/**
* @Author http://torey611.gitee.io/li-tao-feng/
* @Email torey6061@qq.com
* @Date 2021/5/1 15:23
* @描述:
*/
public class EmployeeDao {
public void insert(){
System.out.println(this.getClass().getName() + ".insert();新增数据");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.torey.spring.aop.dao;
/**
* @Author http://torey611.gitee.io/li-tao-feng/
* @Email torey6061@qq.com
* @Date 2021/5/1 15:22
* @描述:
*/
public class UserDao {
public void insert(){
System.out.println(this.getClass().getName() + ".insert();新增数据");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.torey.spring.aop.service;
import com.torey.spring.aop.dao.EmployeeDao;
/**
* @Author http://torey611.gitee.io/li-tao-feng/
* @Email torey6061@qq.com
* @Date 2021/5/1 15:24
* @描述:
*/
public class EmployeeService {
private EmployeeDao employeeDao;
public void entry(){
System.out.println(this.getClass().getName() + ".entry();执行员工入职业务逻辑");
employeeDao.insert();;
}
public EmployeeDao getEmployeeDao() {
return employeeDao;
}
public void setEmployeeDao(EmployeeDao employeeDao) {
this.employeeDao = employeeDao;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.torey.spring.aop.service;
import com.torey.spring.aop.dao.UserDao;
/**
* @Author http://torey611.gitee.io/li-tao-feng/
* @Email torey6061@qq.com
* @Date 2021/5/1 15:23
* @描述:
*/
public class UserService {
private UserDao userDao;
public void createUser(){
if (2==2) {
throw new RuntimeException("用户已存在!!");
}
System.out.println(this.getClass().getName() + ".createUser();执行创建用户业务逻辑");
userDao.insert();
}
public String generateRandomPassWord(String type,Integer length){
System.out.println("按" + type + "方式生成" + length + "位随机密码");
return "ddsseeee";
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.torey.spring.aop;
import com.torey.spring.aop.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Author http://torey611.gitee.io/li-tao-feng/
* @Email torey6061@qq.com
* @Date 2021/5/1 15:55
* @描述:
*/
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService bean = context.getBean("userService", UserService.class);
bean.createUser();
bean.generateRandomPassWord("类型A",5);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userDao" class="com.torey.spring.aop.dao.UserDao"></bean>
<bean id="employeeDao" class="com.torey.spring.aop.dao.EmployeeDao"></bean>
<bean id="userService" class="com.torey.spring.aop.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="employeeService" class="com.torey.spring.aop.service.EmployeeService">
<property name="employeeDao" ref="employeeDao"></property>
</bean>
<!--AOP配置-->
<bean id="methodAspect" class="com.torey.spring.aop.aspect.MethodAspect"></bean>
<aop:config>
<!--pointcut 切点,使用execution表达式描述切面的作用范围-->
<!--execution(public * com.torey..*.*(..)) 说明切面作用在com.torey包下的所有类的所有方法上-->
<aop:pointcut id="pointcut" expression="execution(public * com.torey..*.*(..))"></aop:pointcut>
<!--切面只作用在:后缀为Service类的任意方法-->
<!--<aop:pointcut id="pointcut" expression="execution(public * com.torey..*Service.*(..))"></aop:pointcut>-->
<!--去掉public也是一样的-->
<!--<aop:pointcut id="pointcut" expression="execution(* com.torey..*Service.*(..))"></aop:pointcut>-->
<!--只对返回值为void的方法进行捕获-->
<!--<aop:pointcut id="pointcut" expression="execution(void com.torey..*Service.*(..))"></aop:pointcut>-->
<!--只对返回值为String的方法进行捕获-->
<!--<aop:pointcut id="pointcut" expression="execution(String com.torey..*Service.*(..))"></aop:pointcut>-->
<!--切面只作用在:后缀为Service类的前缀为create任意方法-->
<!--<aop:pointcut id="pointcut" expression="execution(* com.torey..*Service.create*(..))"></aop:pointcut>-->
<!--切面只作用在:后缀为Service类的无参数的任意方法-->
<!--<aop:pointcut id="pointcut" expression="execution(* com.torey..*Service.*())"></aop:pointcut>-->
<!--切面只作用在:后缀为Service类的只有两个参数的任意方法-->
<!--<aop:pointcut id="pointcut" expression="execution(* com.torey..*Service.*(*,*))"></aop:pointcut>-->
<!--切面只作用在:后缀为Service类的只有两个参数的,第一个参数必须为String的任意方法-->
<!--<aop:pointcut id="pointcut" expression="execution(* com.torey..*Service.*(String,*))"></aop:pointcut>-->
<!--定义切面类-->
<aop:aspect ref="methodAspect">
<!--before通知(Advice),代表在目标方法运行前先执行MethodAspect.printExecutionTime()-->
<aop:before method="printExecutionTime" pointcut-ref="pointcut"></aop:before>
<!--后置通知无法获取到目标方法运行过程中所产生的返回值或者是内部抛出的异常,如果需要获取返回值,则需要After Returning Advice(返回后通知),如果需要内部抛出的异常,则需要After Throwing Advice(异常通知)-->
<aop:after method="doAfter" pointcut-ref="pointcut"></aop:after>
<!--返回后通知,可以接收目标方法的返回值; returning="ret": 返回值由哪一个形参接收-->
<!--返回后通知与后置通知的执行顺序:是配置位置的顺序决定的-->
<aop:after-returning method="doAfterReturning" pointcut-ref="pointcut" returning="ret"></aop:after-returning>
<!--异常通知-->
<aop:after-throwing method="doAfterThrowing" pointcut-ref="pointcut" throwing="throwable"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 导航,上一页,下一页
# 支持我-微信扫一扫-加入微信公众号
# 赞赏作者
# 种一棵树,最好的时间是十年前,其次是现在
立志用功,如种树然。方其根芽,犹未有干;及其有干,尚未有枝;枝而后叶,叶而后花、实。初种根时,只管栽培灌溉,勿作枝想,勿作实想。悬想何益?何不忘栽培之功,怕没有枝叶花实?