Spring AOP注解案例及基本原理詳解
這篇文章主要介紹了Spring AOP注解案例及基本原理詳解,文中通過示例代碼介紹的非常詳細(xì)溃卡,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
java
切面:Aspect
切面=切入點+通知。在老的spring版本中通常用xml配置蜒简,現(xiàn)在通常是一個類帶上@Aspect注解瘸羡。切面負(fù)責(zé)將 橫切邏輯(通知) 編織 到指定的連接點中。
目標(biāo)對象:Target
將要被增強的對象搓茬。
連接點:JoinPoint
可以被攔截到的程序執(zhí)行點,在spring中就是類中的方法。
切入點:PointCut
需要執(zhí)行攔截的方法张漂,也就是具體實施了橫切邏輯的方法倒源。切入點的規(guī)則在spring中通過AspectJ pointcut expression language來描述。
切入點與連接點的區(qū)別:連接點是所有可以被"切"的點;切入點是真正要切的點。
通知:Advice
針對切入點的橫切邏輯,包含“around”垢啼、“before”和“after”等不同類型的通知。
通知的作用點如其命名:
before:在切入點之前執(zhí)行
after:在切入點之后執(zhí)行
around:在切入點攔截方法张肾,自定義前后芭析,更靈活
還有一些異常處理的通知,這里不一一舉例
織入:Weaving
將切面和目標(biāo)對象連接起來吞瞪,創(chuàng)建代理對象的過程馁启。spring中用的是動態(tài)代理。假如目標(biāo)對象有接口尸饺,使用jdk動態(tài)代理进统;否則使用cglib動態(tài)代理。
說了這么多概念浪听,看看代碼實現(xiàn)可能會使讀者理解的更深刻一些螟碎,這里簡單寫一個通過注解增強方法的AOP-Demo。
首先是切面類:
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
package com.example.demo.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @author Fcb
* @date 2020/6/20
* @description 切面類=切入點+通知
*/
@Aspect
@Component
public class LogAspect {
? //這個方法定義了切入點
? @Pointcut("@annotation(com.example.demo.aop.anno.MyLog)")
? public void pointCut() {}
? //這個方法定義了具體的通知
? @After("pointCut()")
? public void recordRequestParam(JoinPoint joinPoint) {
? ? for (Object s : joinPoint.getArgs()) {
? ? ? //打印所有參數(shù)迹栓,實際中就是記錄日志了
? ? ? System.out.println("after advice : " + s);
? ? }
? }
? //這個方法定義了具體的通知
? @Before("pointCut()")
? public void startRecord(JoinPoint joinPoint) {
? ? for (Object s : joinPoint.getArgs()) {
? ? ? //打印所有參數(shù)
? ? ? System.out.println("before advice : " + s);
? ? }
? }
? //這個方法定義了具體的通知
? @Around("pointCut()")
? public Object aroundRecord(ProceedingJoinPoint pjp) throws Throwable {
? ? for (Object s : pjp.getArgs()) {
? ? ? //打印所有參數(shù)
? ? ? System.out.println("around advice : " + s);
? ? }
? ? return pjp.proceed();
? }
}
注解:
1
2
3
4
5
6
7
8
9
10
11
12
package com.example.demo.aop.anno;
import java.lang.annotation.*;
/**
* @author Fcb
* @date 2020/6/20
* @description
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MyLog {
}
目標(biāo)類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.demo.aop.target;
import com.example.demo.aop.anno.MyLog;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Fcb
* @date 2020/6/20
* @description
*/
@RestController
public class MockController {
? @RequestMapping("/hello")
? @MyLog
? public String helloAop(@RequestParam String key) {
? ? System.out.println("do something...");
? ? return "hello world";
? }
}
最后是測試類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.example.demo.aop.target;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author Fcb
* @date 2020/6/20
* @description
*/
@SpringBootTest
class MockControllerTest {
? @Autowired
? MockController mockController;
? @Test
? void helloAop() {
? ? mockController.helloAop("aop");
? }
}
控制臺結(jié)果:
around advice : aop
before advice : aop
do something...
after advice : aop