<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring Aop 常見(jiàn)注解和執(zhí)行順序

          共 5850字,需瀏覽 12分鐘

           ·

          2022-03-17 05:17

          來(lái)源:juejin.cn/post/7062506923194581029


          Spring 一開(kāi)始最強(qiáng)大的就是 IOC / AOP 兩大核心功能,我們今天一起來(lái)學(xué)習(xí)一下 Spring AOP 常見(jiàn)注解和執(zhí)行順序。Spring Aop 的常用注解

          首先我們一起來(lái)回顧一下 Spring Aop 中常用的幾個(gè)注解:

          • @Before 前置通知:目標(biāo)方法之前執(zhí)行
          • @After 后置通知:目標(biāo)方法之后執(zhí)行(始終執(zhí)行)
          • @AfterReturning 返回之后通知:執(zhí)行方法結(jié)束之前執(zhí)行(異常不執(zhí)行)
          • @AfterThrowing 異常通知:出香異常后執(zhí)行
          • @Around 環(huán)繞通知:環(huán)繞目標(biāo)方法執(zhí)行

          常見(jiàn)問(wèn)題

          1、你肯定知道 Spring  , 那說(shuō)說(shuō) Aop 的去全部通知順序, Spring Boot 或者 Spring Boot 2 對(duì) aop 的執(zhí)行順序影響?

          2、說(shuō)說(shuō)你在 AOP 中遇到的那些坑?

          示例代碼

          下面我們先快速構(gòu)建一個(gè) spring aop 的 demo 程序來(lái)一起討論 spring aop 中的一些細(xì)節(jié)。

          配置文件

          為了方便我直接使用 spring-boot 進(jìn)行快速的項(xiàng)目搭建,大家可以使用 idea 的spring-boot 項(xiàng)目快速創(chuàng)建功能,或者去 start.spring.io 上面去快速創(chuàng)建spring-boot 應(yīng)用。

          因?yàn)楸救私?jīng)常手動(dòng)去網(wǎng)上貼一些依賴(lài)導(dǎo)致,依賴(lài)沖突服務(wù)啟動(dòng)失敗等一些問(wèn)題。

          plugins {
              id 'org.springframework.boot' version '2.6.3'
              id 'io.spring.dependency-management' version '1.0.11.RELEASE'
              id 'java'
          }

          group 'io.zhengsh'
          version '1.0-SNAPSHOT'

          repositories {
              mavenCentral()
              maven { url 'https://repo.spring.io/milestone' }
              maven { url 'https://repo.spring.io/snapshot' }
          }

          dependencies {
              # 其實(shí)這里也可以不增加 web 配置,為了試驗(yàn)簡(jiǎn)單,大家請(qǐng)忽略 
              implementation 'org.springframework.boot:spring-boot-starter-web'
              implementation 'org.springframework.boot:spring-boot-starter-actuator'
              implementation 'org.springframework.boot:spring-boot-starter-aop'
              
              testImplementation 'org.springframework.boot:spring-boot-starter-test'
          }

          tasks.named('test') {
              useJUnitPlatform()
          }

          接口類(lèi)

          首先我們需要定義一個(gè)接口。我們這里可以再來(lái)回顧一下 JDK 的默認(rèn)代理實(shí)現(xiàn)的選擇:

          • 如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,則默認(rèn)采用JDK動(dòng)態(tài)代理
          • 如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)接口,則采用進(jìn)行動(dòng)態(tài)代理
          • 如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,且強(qiáng)制Cglib,則使用cglib代理

          這塊的邏輯在 DefaultAopProxyFactory 大家有興趣可以去看看。

          public interface CalcService {

              public int div(int x, int y);
          }

          實(shí)現(xiàn)類(lèi)

          這里我門(mén)就簡(jiǎn)單一點(diǎn)做一個(gè)除法操作,可以模擬正常也可以很容易的模擬錯(cuò)誤。

          @Service
          public class CalcServiceImpl implements CalcService {

              @Override
              public int div(int x, int y) {
                  int result = x / y;
                  System.out.println("====> CalcServiceImpl 被調(diào)用了,我們的計(jì)算結(jié)果是:" + result);
                  return result;
              }
          }

          aop 攔截器

          申明一個(gè)攔截器我們要為當(dāng)前對(duì)象增加 @Aspect 和 @Component ,筆者之前也是才踩過(guò)這樣的坑,只加了一個(gè)。

          其實(shí)這塊我剛開(kāi)始也不是很理解,但是我看了 Aspect 注解的定義我就清楚了

          這里面根本就沒(méi)有 Bean 的定義。所以我們還是乖乖的加上兩個(gè)注解。

          還有就是如果當(dāng)測(cè)試的時(shí)候需要開(kāi)啟Aop 的支持為配置類(lèi)上增加@EnableAspectJAutoProxy 注解。

          其實(shí) Aop 使用就三個(gè)步驟:

          • 定義 Aspect 定義切面
          • 定義 Pointcut 就是定義我們切入點(diǎn)
          • 定義具體的通知,比如: @After, @Before 等。
          @Aspect
          @Component
          public class MyAspect {

              @Pointcut("execution(* io.zhengsh.spring.service.impl..*.*(..))")
              public void divPointCut() {

              }

              @Before("divPointCut()")
              public void beforeNotify() {
                  System.out.println("----===>> @Before 我是前置通知");
              }

              @After("divPointCut")
              public void afterNotify() {
                  System.out.println("----===>> @After  我是后置通知");
              }

              @AfterReturning("divPointCut")
              public void afterReturningNotify() {
                  System.out.println("----===>> @AfterReturning 我是前置通知");
              }

              @AfterThrowing("divPointCut")
              public void afterThrowingNotify() {
                  System.out.println("----===>> @AfterThrowing 我是異常通知");
              }

              @Around("divPointCut")
              public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
                  Object retVal;
                  System.out.println("----===>> @Around 環(huán)繞通知之前 AAA");
                  retVal = proceedingJoinPoint.proceed();
                  System.out.println("----===>> @Around 環(huán)繞通知之后 BBB");
                  return retVal;
              }
          }

          測(cè)試類(lèi)

          其實(shí)我這個(gè)測(cè)試類(lèi),雖然用了 @Test 注解,但是我這個(gè)類(lèi)更加像一個(gè) main 方法把:如下所示:

          執(zhí)行結(jié)論

          結(jié)果記錄:spring 4.x, spring-boot 1.5.9

          無(wú)法現(xiàn)在依賴(lài),所以無(wú)法試驗(yàn)

          我直接說(shuō)一下結(jié)論:Spring 4 中環(huán)繞通知是在最里面執(zhí)行的

          結(jié)果記錄:spring 版本5.3.15 springboot 版本2.6.3

          多切面的情況

          多個(gè)切面的情況下,可以通過(guò)@Order指定先后順序,數(shù)字越小,優(yōu)先級(jí)越高。如下圖所示:

          代理失效場(chǎng)景

          下面一種場(chǎng)景會(huì)導(dǎo)致 aop 代理失效,因?yàn)槲覀冊(cè)趫?zhí)行 a 方法的時(shí)候其實(shí)本質(zhì)是執(zhí)行 AServer#a 的方法攔截器(MethodInterceptor)鏈, 當(dāng)我們?cè)?a 方法內(nèi)直接執(zhí)行b(), 其實(shí)本質(zhì)就相當(dāng)于 this.b() , 這個(gè)時(shí)候由執(zhí)行 a方法是調(diào)用到 a 的原始對(duì)象相當(dāng)于是 this 調(diào)用,那么會(huì)導(dǎo)致 b() 方法的代理失效。這個(gè)問(wèn)題也是我們開(kāi)發(fā)者在開(kāi)發(fā)過(guò)程中最常遇到的一個(gè)問(wèn)題。

          @Service
          public class AService {
              
              public void a() {
                  System.out.println("...... a");
                  b();
              }
              
              public void b() {
                  System.out.println("...... b");
              }

          }

          怎么接私活?這個(gè)渠道你100%有用!請(qǐng)收藏!


          點(diǎn)個(gè)在看 
          瀏覽 66
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线国内自拍 | 日本爱爱视频 | 玖玖精品视频在线观看 | 日韩精品在线电影 | 亚洲在线第一页 |