1、AOP指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式。aop底层是动态代理。
代码语言:javascript复制 1 package com.bie.config;
2
3 import org.aspectj.lang.annotation.Aspect;
4 import org.springframework.context.annotation.Bean;
5 import org.springframework.context.annotation.Configuration;
6 import org.springframework.context.annotation.EnableAspectJAutoProxy;
7
8 import com.bie.aop.LogAspect;
9 import com.bie.aop.MathCalculator;
10
11 /**
12 *
13 *
14 * @Title: SpringApplicationConfig.java
15 * @Package com.bie.config
16 * @Description: TODO
17 * @author biehl
18 * @date 2019年12月9日
19 * @version V1.0
20 *
21 *
22 * 1、AOP指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式。aop底层是动态代理。
23 *
24 * 第一步、导入aop模块,spring-aspects。
25 * 第二步、定义业务逻辑类,MathCalculator。在业务逻辑运行的时候打印日志(方法运行之前,方法运行结束,方法出现异常打印日志。)。
26 * 第三步、定义一个日志切面类LogAspect,切面类里面的方法需要动态感知到类的方法MathCalculator.div运行到那一步了。然后开始执行。
27 * 通知方法介绍:
28 * 前置通知:logStart,在目标方法运行之前运行。注解@Before
29 * 后置通知:logEnd,在目标方法运行结束之后运行,无论方法正常结束还是异常结束。注解@After
30 * 返回通知:logReturn,在目标方法运行正常返回之后运行。注解@AfterRetruning
31 * 异常通知:logException,在目标方法运行异常返回之后运行。注解@AfterThrowing
32 * 环绕通知:动态代理。手动推进目标方法运行。 注解@Around
33 * 第四步、根据通知方法给切面类的目标方法标注何时何地运行。标注通知注解。
34 * 第五步、将切面类,和业务逻辑层(目标方法所在的类)都加如到容器中。使用@Bean注解或者@Component注解即可。
35 * 第六步、告诉Spring那个类是切面类。给切面类加一个@Aspect注解。
36 * 第七步、开启基于注解版的aop模式切面功能。启用该注解@EnableAspectJAutoProxy,启动AspectJ自动代理。
37 * @EnableXXX开启某项功能。
38 *
39 * AOP切面编程重要的三步走:
40 * 第一步、将业务逻辑组件和切面类都加入到容器中。告诉spring容器那个是切面类(@Aspect)。
41 * 第二步、在切面类上的每个通知方法上标注通知注解,告诉spring何时何地运行(注意切入点表达式的书写)。
42 * 第三步、开启基于注解版的aop模式切面功能。启用该注解@EnableAspectJAutoProxy,启动AspectJ自动代理。
43 */
44 // @Configuration告诉Spring这是一个配置类,相当于bean.xml配置文件。
45 @Configuration
46 @EnableAspectJAutoProxy
47 public class SpringApplicationConfig15 {
48
49 /**
50 * 将目标类加入到容器中
51 *
52 * @return
53 */
54 @Bean
55 public MathCalculator mathCalculator() {
56 return new MathCalculator();
57 }
58
59
60 /**
61 * 将切面类加入到容器中
62 *
63 * @return
64 */
65 @Bean
66 public LogAspect logAspect() {
67 return new LogAspect();
68 }
69
70 }
开发业务逻辑层类,如下所示:
代码语言:javascript复制 1 package com.bie.aop;
2
3 /**
4 *
5 *
6 * @Title: MathCalculator.java
7 * @Package com.bie.aop
8 * @Description: TODO
9 * @author biehl
10 * @date 2019年12月12日
11 * @version V1.0
12 *
13 */
14 public class MathCalculator {
15
16 /**
17 *
18 * @param i
19 * @param j
20 * @return
21 */
22 public int div(int i, int j) {
23 System.out.println(i " / " j " = " i / j);
24 return i / j;
25 }
26
27 }
开发切面类,如下所示:
代码语言:javascript复制 1 package com.bie.aop;
2
3 import java.util.Arrays;
4
5 import org.aspectj.lang.JoinPoint;
6 import org.aspectj.lang.annotation.After;
7 import org.aspectj.lang.annotation.AfterReturning;
8 import org.aspectj.lang.annotation.AfterThrowing;
9 import org.aspectj.lang.annotation.Aspect;
10 import org.aspectj.lang.annotation.Before;
11 import org.aspectj.lang.annotation.Pointcut;
12
13 /**
14 *
15 *
16 * @Title: LogAspect.java
17 * @Package com.bie.aop
18 * @Description: TODO
19 * @author biehl
20 * @date 2019年12月12日
21 * @version V1.0
22 *
23 * 日志切面类
24 */
25 @Aspect // 告诉Spring容器,当前类是切面类
26 public class LogAspect {
27
28 /**
29 * 抽取公共的切入点表达式
30 *
31 * 方式一,如果是本类引用,直接使用即可,@Before("pointCut()")
32 * 方式二,其他的切面类引入,加上类路径即可@Before("com.bie.aop.LogAspect.pointCut()")
33 */
34 @Pointcut(value = "execution(* com.bie.aop.MathCalculator.*(..))")
35 public void pointCut() {
36 }
37
38 /**
39 * JoinPoint参数必须出现在参数的第一位
40 *
41 * 方法运行前执行该方法。@Before目标方法之前切入。
42 *
43 * 切入点表达式,public int com.bie.aop.MathCalculator.div(int int)。 指定在那个方法切入。
44 *
45 * Signature签名是方法的签名。
46 */
47 @Before(value = "pointCut()")
48 public void logStart(JoinPoint joinPoint) {
49 // 获取到方法参数列表
50 Object[] args = joinPoint.getArgs();
51 // 获取到方法名称
52 String methodName = joinPoint.getSignature().getName();
53 System.out.println(methodName "()方法名称, @Before除法方法执行了......参数列表是{" Arrays.asList(args) "}");
54 }
55
56 /**
57 * JoinPoint参数必须出现在参数的第一位
58 *
59 * 方法运行后执行该方法
60 *
61 * @After(value = "public int com.bie.aop.MathCalculator.*(..)")
62 * 代表了MathCalculator该类的所有方法。所有方法的任意参数。
63 *
64 */
65 @After(value = "pointCut()")
66 public void logEnd(JoinPoint joinPoint) {
67 // 获取到方法参数列表
68 Object[] args = joinPoint.getArgs();
69 // 获取到方法名称
70 String methodName = joinPoint.getSignature().getName();
71 System.out.println(methodName "()方法名称, @After除法方法结束了......参数列表是{" Arrays.asList(args) "}");
72 }
73
74 /**
75 * JoinPoint参数必须出现在参数的第一位
76 *
77 * returning指定谁来封装返回值。
78 *
79 * @param result
80 * 参数封装返回值
81 */
82 @AfterReturning(value = "pointCut()", returning = "result")
83 public void logReturn(JoinPoint joinPoint, Object result) {
84 // 获取到方法名称
85 String methodName = joinPoint.getSignature().getName();
86 System.out.println(methodName "()方法名称, @AfterReturning除法方法正常返回了......运行结果是{" result "}");
87 }
88
89 /**
90 * JoinPoint参数必须出现在参数的第一位
91 *
92 * throwing指定谁来封装返回值。
93 *
94 * @param exception
95 * 参数封装返回值
96 */
97 @AfterThrowing(value = "pointCut()", throwing = "exception")
98 public void logException(JoinPoint joinPoint, Exception exception) {
99 // 获取到方法名称
100 String methodName = joinPoint.getSignature().getName();
101 System.out.println(methodName "()方法名称, @AfterThrowing除法方法异常了......异常信息是{" exception "}");
102 }
103
104 }
测试主类,如下所示:
代码语言:javascript复制 1 package com.bie.main;
2
3 import org.springframework.beans.BeansException;
4 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
5
6 import com.bie.aop.MathCalculator;
7 import com.bie.config.SpringApplicationConfig15;
8
9 /**
10 *
11 *
12 * @Title: SpringApplication.java
13 * @Package com.bie.main
14 * @Description: TODO
15 * @author biehl
16 * @date 2019年12月9日
17 * @version V1.0
18 *
19 */
20 public class SpringApplication {
21
22 public static void main(String[] args) {
23 // 获取到注解配置类
24 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringApplicationConfig15.class);
25
26 try {
27 // 使用容器中获取到目标对象,而不是自己创建对象。
28 MathCalculator mathCalculator = ac.getBean(MathCalculator.class);
29 mathCalculator.div(42, 2);
30 } catch (BeansException e) {
31 e.printStackTrace();
32 }
33
34 // 调用关闭的时候,调用destory销毁方法。
35 ac.close();
36 }
37
38 }