<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
確定專案中包含可以註解的依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
在專案中自定義註解的步驟主要有兩步,第一步:定義註解類,第二步:定義切面
直接建立 @interface的類,使用註解@Target和 @Retention指定其適用範圍及保留時長,如下:
@Target(ElementType.METHOD) // 指定註解的適用範圍 @Retention(RetentionPolicy.RUNTIME) //指定執行時 public @interface ApiLog { String desc() default ""; boolean timeSpan() default true; }
註解類的內容一般很簡單,類似於Enum類一樣,裡面是簡單的方法及屬性
通過@Aspect註解指定一個類,該類必須實現
@Component @Aspect @Slf4j(topic = "ApiLogNote") public class ElasticSearchExecuteLog { @Around("@annotation(com.gcc.ApiLog)") public Object aroundAdvice(ProceedingJoinPoint point) throws Throwable { MethodSignature signature = (MethodSignature) point.getSignature(); //獲取被呼叫方法 Method method = signature.getMethod(); //取出被呼叫方法的註解,方便後續使用註解中的屬性 ApiLog loglinstener = method.getAnnotation(ApiLog.class); log.info("----------------------method[{}]start--------------------",method.getName()); log.info("方法描述:{}",loglinstener.desc()); log.info("引數 :{}",point.getArgs()); long startTime = System.currentTimeMillis(); Object proceed = point.proceed(); long endTime = System.currentTimeMillis(); log.info("耗時:{}ss",endTime-startTime); log.info("----------------------method[{}] end--------------------n",method.getName()) return proceed; } }
因為此例子使用的型別為METHOD即方法級的註解,直接在方法上使用即可:
@ApiLog public JSONObject seachEsData(String indexName, SearchSourceBuilder searchSourceBuilder) { JSONObject resultMap = new JSONObject(); ....... return resultMap; }
註解@Target常常配合列舉類ElementType來指定註解的作用位置,也叫合法位置,即你定義了一個註解,這個註解是類註解還是方法註解還是XX註解等,具體作用的範圍,取決於@Target({ElementType.TYPE})中,ElementType的列舉值,在進行自定義列舉時,根據自己的需求,決定定義的註解是哪類層級使用的註解,例如上面的例子中,@ApiLog這個自定義的註解就是方法級的註解
ElementType的列舉值有
列舉值 | 含義 |
---|---|
TYPE | 類, 介面 (包括註解型別), 或 列舉 宣告 |
FIELD | 欄位、包括列舉常數 |
METHOD | 方法宣告 |
PARAMETER | 正式的引數宣告 |
CONSTRUCTOR | 建構函式的宣告 |
LOCAL_VARIABLE | 區域性變數的宣告 |
ANNOTATION_TYPE | 註解型別的宣告 |
PACKAGE | 包宣告 |
註解@Retention常常配合列舉類RetentionPolic來指定註解的各種策略,註解的保留時間,也就是何時生效,即你定義了一個註解,這個註解是編譯時生效還是僅僅只是在程式碼中標記等等,具體作用的範圍,取決於@Retention({RetentionPolic.TYPE})中,RetentionPolic的列舉值,在進行自定義列舉時,大多數都是使用RUNTIME(編譯時生效)
RetentionPolic的列舉值
列舉值 | 含義 |
---|---|
SOURCE | 解只在原始碼級別保留,編譯時被忽略 |
CLASS | 註解將被編譯器在類檔案中記錄 , 但在執行時不需要JVM保留。這是預設的 |
RUNTIME | 註解將被編譯器記錄在類檔案中,在執行時保留VM,也是使用最多的(一般自定義均使用這個) |
這種在執行時,動態地將程式碼切入到類的指定方法、指定位置上的程式設計思想就是面向切面的程式設計
切面
切面是一個橫切關注點的模組化,一個切面能夠包含同一個型別的不同增強方法,比如說事務處理和紀錄檔處理可以理解為兩個切面。切面由切入點和通知組成,它既包含了橫切邏輯的定義,也包括了切入點的定義。 Spring AOP就是負責實施切面的框架,它將切面所定義的橫切邏輯織入到切面所指定的連線點中。簡單點理解,在SpringBoot中使用了Aspect註解的類就是切面
@Component @Aspect public class LogAspect { }
目標物件
目標物件指將要被增強的物件,即包含主業務邏輯的類物件。或者說是被一個或者多個切面所通知的物件。
在我們的例子中,即是使用了@ApiLog註解的地方
連線點
程式執行過程中明確的點,如方法的呼叫或特定的異常被丟擲。連線點由兩個資訊確定:
方法(表示程式執行點,即在哪個目標方法)
相對點(表示方位,即目標方法的什麼位置,比如呼叫前,後等)
簡單來說,連線點就是被攔截到的程式執行點,因為Spring只支援方法型別的連線點,所以在Spring中連線點就是被攔截到的方法。
切入點
切入點是對連線點進行攔截的條件定義。切入點表示式如何和連線點匹配是AOP的核心,Spring預設使用AspectJ切入點語法。 一般認為,所有的方法都可以認為是連線點,但是我們並不希望在所有的方法上都新增通知,而切入點的作用就是提供一組規則(使用 AspectJ pointcut expression language 來描述) 來匹配連線點,給滿足規則的連線點新增通知。
//此處的匹配規則是 com.remcarpediem.test.aop.service包下的所有類的所有函數。 @Pointcut("execution(* com.remcarpediem.test.aop.service..*(..))") public void pointcut() { }
這裡切入點的概念其實就是確定對哪些目標物件進行切面插入功能,一開始的例子是採用註解的方式來達到切入**點的作用
@Around("@annotation(com.gcc.ApiLog)")
通知
通知是指攔截到連線點之後要執行的程式碼,包括了“around”、“before”和“after”等不同型別的通知。Spring AOP框架以攔截器來實現通知模型,並維護一個以連線點為中心的攔截器鏈。
// @Before說明這是一個前置通知,log函數中是要前置執行的程式碼,JoinPoint是連線點, @Before("pointcut()") public void log(JoinPoint joinPoint) { } //@After 為後置通知 //@Around 為環繞通知
織入(Weaving)
這裡的織入概念是個動作,即Spring將前面的切面、連線點、切入點關聯起來並建立通知代理的過程。織入可以在編譯時,類載入時和執行時完成。在編譯時進行織入就是靜態代理,而在執行時進行織入則是動態代理。
增強器(Advisor)
Advisor是切面的另外一種實現,能夠將通知以更為複雜的方式織入到目標物件中,是將通知包裝為更復雜切面的裝配器。Advisor由切入點和Advice組成。 Advisor這個概念來自於Spring對AOP的支撐,在AspectJ中是沒有等價的概念的。Advisor就像是一個小的自包含的切面,這個切面只有一個通知。切面自身通過一個Bean表示,並且必須實現一個預設介面。
簡單來講,整個 aspect 可以描述為: 滿足 pointcut 規則的 joinpoint 會被新增相應的 advice 操作。
將上方通過註解使用切面的方式改寫一下:
@Component @Aspect @Sl4fj public class ElasticSearchExecuteLog { // 不使用註解,而通過基礎的規則設定選擇切入點,表示式是指com.gcc.controller // 包下的所有類的所有方法 @Pointcut("execution(* com.gcc.controller..*(..))") public void aspect() {} // 通知,在符合aspect切入點的方法前插入如下程式碼,並且將連線點作為引數傳遞 @Before("aspect()") public void log(JoinPoint joinPoint) { //連線點作為引數傳入 // 獲得類名,方法名,引數和引數名稱。 Signature signature = joinPoint.getSignature(); String className = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); String[] argumentNames = methodSignature.getParameterNames(); StringBuilder sb = new StringBuilder(className + "." + methodName + "("); for (int i = 0; i< arguments.length; i++) { Object argument = arguments[i]; sb.append(argumentNames[i] + "->"); sb.append(argument != null ? argument.toString() : "null "); } sb.append(")"); log.info(sb.toString()); } }
JoinPoint物件
JoinPoint物件封裝了SpringAop中切面方法的資訊,在切面方法中新增JoinPoint引數,就可以獲取到封裝了該方法資訊的JoinPoint物件.
方法 | 作用 | 返回物件 |
---|---|---|
getSignature() | 獲取封裝了署名資訊的物件,在該物件中可以獲取到目標方法名,所屬類的Class等資訊 | Signature |
getArgs() | 獲取 獲取傳入目標方法的引數物件 | Object[] |
getTarget() | 獲取被代理的物件 | Object |
proceedingJoinPoin物件
proceedingJoinPoin物件是JoinPoint的子類,在原本JoinPoint的基礎上,放開了Proceeed()的使用,一般在環繞通知@Around時使用:
Object proceed() throws Throwable //執行目標方法 Object proceed(Object[] var1) throws Throwable //傳入的新的引數去執行目標方法
以上就是SpringBoot搭配AOP實現自定義註解的詳細內容,更多關於SpringBoot AOP自定義註解的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45