91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring AOP的概念及用法

發布時間:2021-08-24 17:19:58 來源:億速云 閱讀:175 作者:chen 欄目:開發技術

這篇文章主要講解了“Spring AOP的概念及用法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Spring AOP的概念及用法”吧!

目錄
  • 什么是AOP?

  • AOP術語

    • 通知(Advice)

    • 連接點(Join point)

    • 切點(Pointcut)

      • 連接點和切點的區別

    • 切面(Aspect)

      • 引入(Introduction)

        • 織入(Weaving)

        • SpringAOP

          • SpringAOP的特點

            • SpringBoot集成SpringAOP

              • - 依賴引入

              • - 創建注解

              • - 定義切面

              • - 設置切點

              • - 業務接口編寫

              • - 測試

            • 通知時機

              • - 正常情況

              • - 異常情況


          什么是AOP?

          AOP,即我們平時經常提到的面向切面編程。首先我們要理解一個叫橫切關注點(cross-cutting concern)的概念,它其實是描述我們應用中的功能,假如有一個功能,它在應用程序中很多個地方都用了,那么我們把這樣的功能稱之為橫切關注點。

          日常開發中,我們都會將不同的業務場景抽象出對應的模塊進行開發,而不同的模塊,除了那些針對特定領域的核心功能外,還有一些相同的輔助功能,比如日志管理、安全管理、事務管理等等。橫切關注點這個概念其實就點明了:類似這樣的功能就是我們面向切面編程需要關注的地方。這也是面向切面編程的意義所在:它幫助我們實現橫切關注點和他們所影響的對象之間的解耦。

          面向切面編程的實質,就是講橫切關注點模塊化成稱為切面的特殊的類。

          AOP術語

          以下討論都基于SpringAOP

          通知(Advice)

          切面的工作被稱為通知。也就是定義了切面的要做什么,以及何時做的問題。下面是Spring切面有5種類型的通知,以及相對應的在SpringBoot中的五個注解

          • 前置通知(Before):方法調用之前,對應@Before

          • 后置通知(After):方法調用之后(不關心方法輸出是什么)對應@After

          • 返回通知(After-returning):目標方法成功執行之后,對應@AfterReturning

          • 異常通知(After-throwing):目標方法拋出異常之后,對應@AfterThrowing

          • 環繞通知(Around):方法調用之前和之后,對應@Around

          • 后置通知和返回通知的區別

          后置通知應用時機在返回通知之后,任何情況下都會應用,而返回通知只有方法正常執行

          正常返回后執行

          • 環繞通知與其它通知的區別

          不同于其它的通知,環繞通知有目標方法的執行權,能夠控制目標方法是否執行。而其它的通知更多是對目標方法的一個增強,無法影響目標方法的執行

          以上兩點,我們下面會通過一個例子更好的體會其中的差異。

          連接點(Join point)

          程序中那些我們想要應用通知的地方,就是連接點。這個點可以是我們調用方法時、拋出異常時或甚至是修改某一個字段的時候。切面代碼(通知)可以通過這些點插入到應用的正常流程中,是原本的功能增添新的行為。

          切點(Pointcut)

          我們的應用程序可能會有很多個連接點需要我們應用通知,所以我們有必要把連接點的分類匯總,抽象出相同的特點,好讓正確的切面切入到正確的地方去,各司其職,而不是切入所有的連接點。切點定義 了一個切面需要在哪里進行切入。是一堆具有特定切面切入需求的連接點的共性抽象。

          我們通常通過明確類和方法名、或者匹配正則表達式的方式來指定切點

          連接點和切點的區別

          切點是對的擁有相同特點的連接點集合的一個抽象。切點定義了連接點的特性,是一個描述性的歸納,由于在SpringAOP中切點的切入級別是方法,所以那些符合切點定義的方法,都是一個連接點,連接點是切點的具象表現。

          切面(Aspect)

          切面是通知和切點的結合。通知和切點共同定了切面的全部內容——它想要干什么,在何時何地完成功能。

          引入(Introduction)

          引入能夠讓我們在不修改原有類的代碼的基礎上,添加生的方法或屬性。

          織入(Weaving)

          織入是把切面應用到目標對象并創建新的代理對象的過程。

          SpringAOP

          SpringAOP的特點

          SpringAOP是通過動態代理實現的。不同于AspectJ等其他aop框架,SpringAOP只支持方法級別的切點,不支持類構造器或字段級別的切點。因此只能攔截方法進行通知,而在對象創建或對象變量的修改時,都無法應用通知

          SpringBoot集成SpringAOP

          SpringBoot引入AOP依賴后,spring.aop.auto屬性默認是開啟的,也就是說只要引入了AOP依賴后,默認已經增加了@EnableAspectJAutoProxy

          Spring AOP的概念及用法

          現在我們來設想一個場景:我有若干個業務場景,每個場景對應一個服務,有些服務需要我在調服務的時候,打印開始和結束信息,并輸入服務處理的時長。

          - 依賴引入

          首先在項目中引入SpringAOP的依賴:

          <!--引入AOP依賴-->
          <dependency>
          	<groupId>org.springframework.boot</groupId>
          	<artifactId>spring-boot-starter-aop</artifactId>
          </dependency>
          - 創建注解

          創建一個自定義注解@ApiLog,用boolean類型的字段來決定是否開啟日志輸入功能,代碼如下:

          @Target({ElementType.TYPE, ElementType.METHOD})
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          public @interface ApiLog {
              boolean isOn() default true;
          }
          - 定義切面

          定義一個切面類MyAspect.java,代碼如下

          @Aspect
          @Component
          public class MyAspect {
          
              @Pointcut("execution(* com.acelin.hello.study.springTest.aop.AspectController.*(..))")
              private void onePointcut(){}
          
              @Around("onePointcut()")
              public Object around(ProceedingJoinPoint point)throws Throwable{
          
                  Signature signature = point.getSignature();
                  MethodSignature methodSignature = (MethodSignature) signature;
                  Method method = methodSignature.getMethod();
          
                  /* 獲取方法上的注解 */
                  ApiLog apiLog = method.getAnnotation(ApiLog.class);
                  if (apiLog != null && apiLog.isOn()){
                      System.out.println("ApiLog is on!");
                  }
          
                  Object[] objects = point.getArgs();
                  String bussinessName = (String) objects[0];
                  System.out.println("-- " + bussinessName + " start --");
                  long begin = System.currentTimeMillis();
                  Object object = point.proceed();
                  long end = System.currentTimeMillis();
                  System.out.println("-- " + bussinessName + " end  耗時" + (end - begin) + "ms --");
                  return object;
              }
          }
          - 設置切點
          @Pointcut("execution(* com.acelin.hello.study.springTest.aop.AspectController.*(..))")
          private void onePointcut(){}

          @Pointcut注解表示聲明一個切點,然后我們要配置execution指示器,它用來匹配所有符合條件的連接點。已上面的指示器配置* com.acelin.hello.study.springTest.aop.AspectController.*(..)為例,分析一下指示器的寫法

          • 第一個*號:表示的不關心方法的返回值類型

          • 中間的com.acelin.hello.study.springTest.aop.AspectController.*指定方法的特點

          • 第二個*號:表示AspectController類下的任意方法

          • (..):表示不關心參數個數和類型

          - 業務接口編寫

          我們寫一個簡單的接口,然后注釋我們自定義的注解,開啟相關日志的輸出。

          @RestController
          @RequestMapping("/aop")
          public class AspectController implements IAspect{
          
              @RequestMapping("/test/1/{businessName}")
              @ApiLog(isOn = true)
              public void testAop(@PathVariable("businessName") String businessName){
                  System.out.println("This is a controller about aop test!");
              }
          }
          - 測試

          測試結果如下:

          ApiLog is on!
          -- 業務1 start --
          This is a controller about aop test!
          -- 業務1 end  耗時5ms --

          通知時機

          以上我們通過一個簡單的例子,初步體驗了aop的魅力。接下來我們來討論以下各類通知的特點以及應用時機問題。我們對的上面的切面類進行了修改,加上所有類型的通知。

          @Aspect
          @Component
          public class MyAspect {
          
              @Pointcut("execution(* com.acelin.hello.study.springTest.aop.AspectController.*(..))")
              private void onePointcut(){}
          
              @Before("onePointcut()")
              public void before(){
                  System.out.println("-- before");
              }
          
              @After("onePointcut()")
              public void after(JoinPoint joinPoint) throws NoSuchMethodException{
                  System.out.println("-- after");
              }
              
              @AfterThrowing("onePointcut()")
              public void afterThrowing(){
                  System.out.println("-- afterThrowing");
              }
          
              @AfterReturning("onePointcut()")
              public void afterReturning(){
                  System.out.println("-- afterReturning");
              }
              
              @Around("onePointcut()")
              public Object around(ProceedingJoinPoint point)throws Throwable{
          
                  Signature signature = point.getSignature();
                  MethodSignature methodSignature = (MethodSignature) signature;
                  Method method = methodSignature.getMethod();
          
                  /* 獲取方法上的注解 */
                  ApiLog apiLog = method.getAnnotation(ApiLog.class);
                  if (apiLog != null && apiLog.isOn()){
                      System.out.println("ApiLog is on!");
                  }
          
                  Object[] objects = point.getArgs();
                  String bussinessName = (String) objects[0];
                  System.out.println("-- " + bussinessName + " start");
                  long begin = System.currentTimeMillis();
                  Object object = point.proceed();
                  long end = System.currentTimeMillis();
                  System.out.println("-- " + bussinessName + " end  耗時" + (end - begin) + "ms");
                  return object;
              }
          }

          然后修改接口,怎加業務名稱的一個長度判斷,如果名稱太長,拋出異常,來模擬方法執行過程中法僧異常

          @RequestMapping("/test/1/{businessName}")
          @ApiLog
          public void testAop(@PathVariable("businessName") String businessName){
              System.out.println("This is a controller about aop test!");
              if (businessName.length() > 4){
                  throw new RuntimeException("業務名稱太長!");
              }
          }
          - 正常情況

          來看一下當方法正常執行的情況下,前置通知、后置通知、返回通知和環繞通知的應用時機。

          再次調用測試接口,可看到如下結果:

          ApiLog is on!
          -- 業務 start
          -- before
          This is a controller about aop test!
          -- afterReturning
          -- after
          -- 業務 end  耗時6ms

          - 異常情況

          然后我們修改業務名稱為,使其超過規定長度導致觸發異常拋出,結果如下:

          ApiLog is on!
          -- 超級復雜的業務 start
          -- before
          This is a controller about aop test!
          -- afterThrowing
          -- after

          java.lang.RuntimeException: 業務名稱太長!

           at com.acelin.hello.study.springTest.aop.AspectController.testAop(AspectController.java:16)

          從上面結果可以看出的,前置通知應用于目標方法執行前,然后當方法正常執行時,會在方法結束前執行返回通知,如果發生異常,執行異常通知,返回通知不執行(因為方法已經中斷,不正常返回),而后置通知的是不管方法執行情況,都會在方法結束后執行。環繞通知則包裹著以上所有流程。

          感謝各位的閱讀,以上就是“Spring AOP的概念及用法”的內容了,經過本文的學習后,相信大家對Spring AOP的概念及用法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

          向AI問一下細節

          免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

          AI

          高清| 湘乡市| 望奎县| 榆树市| 深水埗区| 洪雅县| 郓城县| 韩城市| 靖西县| 鄂温| 山东省| 石嘴山市| 义乌市| 菏泽市| 潼南县| 盐亭县| 济源市| 东安县| 龙泉市| 金华市| 泾源县| 台南县| 临泽县| 大渡口区| 合山市| 连江县| 玉门市| 安仁县| 土默特右旗| 万山特区| 兴文县| 南皮县| 大理市| 常熟市| 湟中县| 肥西县| 沅江市| 迁安市| 海伦市| 丽水市| 大足县|