一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - spring中AOP 注解開發示例詳解

spring中AOP 注解開發示例詳解

2020-08-12 10:53橘子不酸 Java教程

這篇文章主要介紹了spring中AOP注解開發的相關資料,文中介紹的很詳細,需要的朋友可以參考借鑒,下面來一起看看吧。

一、簡介

AOP主要包含了通知、切點和連接點等術語,介紹如下:

通知(advice)

通知定義了切面是什么以及何時調用,何時調用包含以下幾種

  • Before 在方法被調用之前調用通知
  • After 在方法完成之后調用通知,無論方法執行是否成功
  • After-returning 在方法成功執行之后調用通知
  • After-throwing 在方法拋出異常后調用通知
  • Around 通知包裹了被通知的方法,在被通知的方法調用之前和調用之后執行自定義的行為

切點(PointCut)

通知定義了切面的什么和何時,切點定義了何處,切點的定義會匹配通知所要織入的一個或多個連接點,
我們通常使用明確的類的方法名稱來指定這些切點,或是利用正則表達式定義匹配的類和方法名稱來指定這些切點。

連接點(JoinPoint)

連接點是在應用執行過程中能夠插入切面的一個點,這個點可以是調用方法時,拋出異常時,甚至是修改一個字段時,
切面代碼可以利用這些連接點插入到應用的正常流程中,并添加新的行為,如日志、安全、事務、緩存等。

  • joinPoint.getSignature().getDeclaringTypeName() 可以獲取到調用方法的類名(包括包名),
  • joinPoint.getSignature().getName()    可以獲取方法名,
  • Arrays.toString(joinPoint.getArgs())   得到的是方法調用的參數列表,
  • joinPoint.proceed()   可以得到方法的返回結果

二、注解開發

聲明一個切面,只需要在類名上添加@Aspect屬性即可,具體的連接點,我們用@Pointcut和@Before、@After等標注。
在聲明前 我們需要依賴配置pom

?
1
2
3
4
5
6
7
8
9
10
<dependency>
 <groupId>org.aspectj</groupId>
 <artifactId>aspectjrt</artifactId>
 <version>1.6.11</version>
</dependency>
<dependency>
 <groupId>org.aspectj</groupId>
 <artifactId>aspectjweaver</artifactId>
 <version>1.6.11</version>
</dependency>

例子

?
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
package com.ganji.demo.service.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Service;
/**
 * Created by admin on 2015/9/2.
 */
@Aspect
@Service
public class XmlAopDemoUserLog {
// 配置切點 及要傳的參數
 @Pointcut("execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..)) && args(id)")
 public void pointCut(int id)
 {
 }
// 配置連接點 方法開始執行時通知
 @Before("pointCut(id)")
 public void beforeLog(int id) {
  System.out.println("開始執行前置通知 日志記錄:"+id);
 }
// 方法執行完后通知
 @After("pointCut(id)")
 public void afterLog(int id) {
  System.out.println("開始執行后置通知 日志記錄:"+id);
 }
// 執行成功后通知
 @AfterReturning("pointCut(id)")
 public void afterReturningLog(int id) {
  System.out.println("方法成功執行后通知 日志記錄:"+id);
 }
// 拋出異常后通知
 @AfterThrowing("pointCut(id)")
 public void afterThrowingLog(int id) {
  System.out.println("方法拋出異常后執行通知 日志記錄"+id);
 }
// 環繞通知
 @Around("pointCut(id)")
 public Object aroundLog(ProceedingJoinPoint joinpoint,int id) {
  Object result = null;
  try {
   System.out.println("環繞通知開始 日志記錄"+id);
   long start = System.currentTimeMillis();
   //有返回參數 則需返回值
   result = joinpoint.proceed();
   long end = System.currentTimeMillis();
   System.out.println("總共執行時長" + (end - start) + " 毫秒");
   System.out.println("環繞通知結束 日志記錄");
  } catch (Throwable t) {
   System.out.println("出現錯誤");
  }
  return result;
 }
}

AOP切面中的同步問題

在WebLogAspect切面中,分別通過doBefore和doAfterReturning兩個獨立函數實現了切點頭部和切點返回后執行的內容,
若我們想統計請求的處理時間,就需要在doBefore處記錄時間,并在doAfterReturning處通過當前時間與開始處記錄的時間計算
得到請求處理的消耗時間。

那么我們是否可以在WebLogAspect切面中定義一個成員變量來給doBefore和doAfterReturning一起訪問呢?是否會有同步問題呢?

的確,直接在這里定義基本類型會有同步問題,所以我們可以引入ThreadLocal對象,像下面這樣進行記錄:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Aspect
@Component
public class WebLogAspect {
 private Logger logger = Logger.getLogger(getClass());
 ThreadLocal<Long> startTime = new ThreadLocal<>();
 @Pointcut("execution(public * com.juzi.web..*.*(..))")
 public void webLog(){}
 @Before("webLog()")
 public void doBefore(JoinPoint joinPoint) throws Throwable {
  startTime.set(System.currentTimeMillis());
  // 省略日志記錄內容
 }
 @AfterReturning(returning = "ret", pointcut = "webLog()")
 public void doAfterReturning(Object ret) throws Throwable {
  // 處理完請求,返回內容
  logger.info("RESPONSE : " + ret);
  logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
 }
}

AOP切面的優先級

由于通過AOP實現,程序得到了很好的解耦,但是也會帶來一些問題,比如:我們可能會對Web層做多個切面,校驗用戶,
校驗頭信息等等,這個時候經常會碰到切面的處理順序問題。

所以,我們需要定義每個切面的優先級,我們需要@Order(i)注解來標識切面的優先級。i的值越小,優先級越高。
假設我們還有一個切面是CheckNameAspect用來校驗name必須為didi,我們為其設置@Order(10),
而上文中WebLogAspect設置為@Order(5),所以WebLogAspect有更高的優先級,這個時候執行順序是這樣的:

在@Before中優先執行@Order(5)的內容,再執行@Order(10)的內容

在@After和@AfterReturning中優先執行@Order(10)的內容,再執行@Order(5)的內容

所以我們可以這樣子總結:

  1. 在切入點前的操作,按order的值由小到大執行
  2. 在切入點后的操作,按order的值由大到小執行

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。

原文鏈接:https://yangzhiw.github.io/2016/07/28/spring-AOP-注解開發/

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 色欲麻豆国产福利精品 | 国产精品nv在线观看 | 韩国帅男同gay网站 韩国三级在线播放 | 成人免费福利网站在线看 | 亚洲第一福利视频 | 男人j放进女人的p视频免费 | 国产精品九九久久一区hh | gay男强壮军人chinese | 日本深夜影院 | 九九精品影院 | 九九热在线免费观看 | 五月色婷婷在线影院 | 5g影院天天影院天天爽影院网站 | 精品一卡2卡3卡4卡5卡亚洲 | 色橹 | 教室眠催白丝美女校花 | 亚洲高清在线视频 | 国产日韩精品一区二区三区 | 日日干天天爽 | 国产精品免费看久久久香蕉 | 国产麻豆精品入口在线观看 | 四虎在线成人免费网站 | 隔壁的漂亮邻居hd中文 | 精品久久久噜噜噜久久久app | 男男18视频免费网站 | 亚洲 欧美 国产 综合 在线 | 美女靠逼免费视频 | 亚洲mm色国产网站 | 韩国一区二区三区 | 久久精品动漫网一区二区 | 日本一本草久p | 好吊色青青青国产综合在线观看 | 国产精品久久久久久久福利院 | 久久r视频 | 91香蕉影院 | 男gay网站视频免费观看 | 国产在线播放91 | 国产精品亚洲精品青青青 | 免费又爽又黄禁片视频在线播放 | 国外成品精品1688 | 国产成人无精品久久久 |