<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Spring之AOP(面向切面編程)

      1、AOP的基本介紹

      AOP是Aspect Oriented Programming,即面向切面編程。AOP是OOP(面向對象編程)的延續,利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。OOP作為面向對象編程的模式,獲得了巨大的成功,OOP的主要功能是數據封裝、繼承和多態。而AOP是一種新的編程方式,它和OOP不同,OOP把系統看作多個對象的交互,AOP把系統分解為不同的關注點,或者稱之為切面(Aspect)。

      AOP 要達到的效果是,保證開發者在不修改源代碼的前提下,去為系統中的業務組件添加某種通用功能。AOP 的本質是由 AOP 框架修改業務組件的多個方法的源代碼。

      AOP技術看上去比較神秘,但實際上,它本質就是一個動態代理。

       

      1.1、spring AOP的代理機制

      按照 AOP 框架修改源代碼的時機,可以將其分為兩類:

      • 靜態 AOP 實現:AOP 框架在編譯階段對程序源代碼進行修改,生成了靜態的 AOP 代理類。此時生成的 *.class 文件已經被改掉了,需要使用特定的編譯器,比如 AspectJ。
      • 動態 AOP 實現:AOP 框架在運行階段對動態生成代理對象,在內存中以 JDK 動態代理,或 CGlib 動態地生成 AOP 代理類,如 SpringAOP。目標對象和切面都是普通Java類,通過JVM的動態代理功能或者第三方庫實現運行期動態織入。

      最簡單的方式就是動態 AOP 實現,Spring的AOP實現就是基于JVM的動態代理。JVM的動態代理要求必須實現接口,所以如果一個普通類并沒有實現任何借口,那么就需要通過CGLIB或者Javassist這些第三方庫來實現 AOP。

      如果要被代理的對象是個實現類,Spring 會自動使用JDK動態代理來完成操作(Spirng默認采用JDK動態代理實現機制);如果要被代理的對象是個普通類,即不是實現類,那么 Spring 會強制使用 CGLib 來實現動態代理。

       

      通過配置Spring的中<aop:config>標簽可以顯式地指定使用什么代理機制,proxy-target-class=true 表示使用CGLib代理,如果為 false 就是默認使用JDK動態代理:

       

      1.2、AOP相關術語

      AOP 領域中的特性術語:

      • 通知(Advice,增強): 通知描述了切面何時執行以及如何執行增強處理。(比如給類中的某個方法進行了添加了一些額外的操作,這些額外操作就是增強)
      • 連接點(join point): 應用執行過程中能夠插入切面的一個點,這個點可以是方法的調用、異常的拋出。在 Spring AOP 中,連接點總是方法的調用,即哪些方法可以被增強,這些方法就可以稱之為一個連接點。
      • 切入點(PointCut): 可以插入增強處理的連接點。實際被真正增強了的方法,稱為切入點。(連接點都可被增強,但實際應用可能只增強了類中的某個方法,則該方法就被稱為切入點)
      • 切面(Aspect): 切面是通知和切點的結合。把通知(增強)應用到切入點的過程就稱為切面。
      • 引入(Introduction):引入允許我們向現有的類添加新的方法或者屬性。
      • 織入(Weaving): 將增強處理添加到目標對象中,并創建一個被增強的對象,這個過程就是織入。

       

      1.3、通知的五種類型(@Before、@After、@AfterReturning、@AfterThrowing、@Around)

      通知(增強)有五種類型:

      1. 前置通知(@Before):在目標方法運行之前運行。目標代碼有異常也會執行,但如果攔截器拋異常,那么目標代碼就不執行了;
      2. 后置通知(@After):在目標方法運行結束之后運行。無論目標代碼是否拋異常,攔截器代碼都會執行;
      3. 返回通知(@AfterReturning):在目標方法正常返回之后運行。和@After不同的是,只有當目標代碼正常返回時,才執行攔截器代碼,并且這個通知執行順序在 @After 之后
      4. 異常通知(@AfterThrowing):在目標方法出現異常之后運行。和@After不同的是,只有當目標代碼拋出了異常時,才執行攔截器代碼;
      5. 環繞通知(@Around):增強的方法會將目標方法封裝起來,能控制是否執行目標代碼,并可以在執行前后、拋異常后執行任意攔截代碼,可以說是包含了上面所有功能。

       

      2、AOP的基本使用

      2.1、切入點表達式

      切入點表達式是 spring 用表達式來對指定的方法進行攔截。

      示例如下:

      execution([權限修飾符] [返回類型(可省略)] [完整類名].[方法名](參數列表))
      
      //示例如下,權限修飾符可用*表示任意權限,參數列表可用 .. 表示方法中的參數
      execution(public int com.demo.Test.*(..))  //作用于Test類中的所有方法
      
      execution(* com.demo.Test.add(..))  //作用于Test類中的add方法
      
      execution(* com.demo.*.*(..))  //作用于demo包下的所有類的所有方法

       

      2.2、AOP的使用

      spring 框架一般都是基于 AspectJ 實現 AOP 操作,AspectJ 不是 spring 的組成部分,一般把 AspectJ 和 spring 框架一起使用,進行 AOP 操作。

      基于 AspectJ  實現 AOP 操作有兩種方式:

      1. 基于XML配置文件實現
      2. 基于注解方式實現

       

      先導入依賴包,spring 實現AOP不僅僅需要自己的jar包,還需要第三方的jar,將這三個jar包放入項目中就可以spring的aop編程了,如下所示:

       

      使用示例:

      先創建一個類(被增強的類):

      package webPackage;
      
      import org.springframework.stereotype.Component;
      
      //需要被增強的類
      @Component
      public class User {
          public void add() {
              System.out.println("user add...");
          }
      }

      然后創建增強類(切面類,編寫增強邏輯):

      package webPackage;
      
      import org.aspectj.lang.annotation.Aspect;
      import org.aspectj.lang.annotation.Before;
      import org.springframework.stereotype.Component;
      
      @Component
      @Aspect  //生成代理對象
      public class UserProxy {
      
          //前置通知
          @Before("execution(* webPackage.User.add(..))")
          public void beforeHandler() {
              System.out.println("前置處理。。。");
          }
      }

      在 xml 配置文件中引入命名變量,并且開啟組件注解掃描和 aspectj 切面支持:

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                                 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
                                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
      
          <!--開啟組件掃描-->
          <context:component-scan base-package="testMain, service, dao, webPackage"></context:component-scan>
      
          <!-- 開啟aspectj切面支持 -->
          <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      </beans>

      驗證代碼:

      package testMain;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      import webPackage.User;
      
      public class Test01 {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("bean01.xml");
      
              User user = (User) context.getBean("user");
              user.add();   //將輸出 前置處理。。。  user add...
      
          }
      }

       

      如果 User 類實現了某個接口,即是實現類,上面的用法可能會報錯: com.sun.proxy.$Proxy11 cannot be cast to web.User。報錯是因為不能用接口的實現類(Target)來轉換Proxy的實現類,它們是同級,應該用共同的接口來轉換。將獲得Bean的接收類型改成接口類型即可。

      此時可以這么用:

      package test;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      import web.User;
      import web.UserInter;
      
      public class Test {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("bean01.xml");
              UserInter user = (UserInter) context.getBean("user");
              user.add();   //將輸出 前置處理。。。  user add...
          }
      }

       

      上面實現的是前置通知,其他類型通知如下:

      package webPackage;
      
      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.*;
      import org.springframework.stereotype.Component;
      
      @Component
      @Aspect  //生成代理對象
      public class UserProxy {
      
          //前置通知
          @Before("execution(* webPackage.User.add(..))")
          public void beforeHandler() {
              System.out.println("前置處理。。。");
          }
      
          //后置通知
          @After("execution(* webPackage.User.add(..))")
          public void afterHandler() {
              System.out.println("后置處理。。。");
          }
      
          //返回通知
          @AfterReturning("execution(* webPackage.User.add(..))")
          public void afterReturnHandler() {
              System.out.println("返回處理。。。");
          }
      
          //異常通知
          @AfterThrowing("execution(* webPackage.User.add(..))")
          public void afterThrowReturnHandler() {
              System.out.println("異常處理。。。");
          }
      
          //環繞通知
          @Around("execution(* webPackage.User.add(..))")
          public void aroundThrowReturnHandler(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
              System.out.println("環繞之前。。。");
      
              proceedingJoinPoint.proceed();  //執行目標方法
      
              System.out.println("環繞之后。。。");
          }
      }

      執行結果:環繞之前。。。     前置處理。。。    user add...     環繞之后。。。   后置處理。。。   返回處理。。。

      異常通知沒有執行,因為目標方法并沒有拋出異常,如果拋出異常,異常通知才會執行。

       

      2.3、抽取相同切入點(@Pointcut)

      使用多個通知時,可能需要重復寫切入點表達式,此時我們可以通過 @Pointcut 注解來將切入點抽取出來進行復用:

      package webPackage;
      
      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.*;
      import org.springframework.stereotype.Component;
      
      @Component
      @Aspect  //生成代理對象
      public class UserProxy {
      
          @Pointcut("execution(* webPackage.User.add(..))")
          public void pointDemo() {}
      
          //前置通知
          @Before("pointDemo()")
          public void beforeHandler() {
              System.out.println("前置處理。。。");
          }
      
          //后置通知
          @After("pointDemo()")
          public void afterHandler() {
              System.out.println("后置處理。。。");
          }
      }

       

      2.4、多個切面(增強類)優先級

      如果有多個切面對同一個類的方法都進行了增強,我們可以用 @Order(num) 來定義各個切面的優先級,num越小,優先級越高。

      比如 UserProxy 和 UserProxy02 都對 User 的 add 方法進行了增強,我們就可以通過 @Order(num) 來指定哪個增強類先執行:

      UserProxy 代碼:

      package webPackage;
      
      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.*;
      import org.springframework.core.annotation.Order;
      import org.springframework.stereotype.Component;
      
      @Component
      @Aspect 
      @Order(2)
      public class UserProxy {
      
          @Pointcut("execution(* webPackage.User.add(..))")
          public void pointDemo() {}
      
          //前置通知
          @Before("pointDemo()")
          public void beforeHandler() {
              System.out.println("UserProxy 的前置處理。。。");
          }
      }

      UserProxy02 代碼:

      package webPackage;
      
      import org.aspectj.lang.annotation.Aspect;
      import org.aspectj.lang.annotation.Before;
      import org.aspectj.lang.annotation.Pointcut;
      import org.springframework.core.annotation.Order;
      import org.springframework.stereotype.Component;
      
      @Component
      @Aspect  //生成代理對象
      @Order(1)
      public class UserProxy02 {
          @Pointcut("execution(* webPackage.User.add(..))")
          public void pointDemo() {}
      
          //前置通知
          @Before("pointDemo()")
          public void beforeHandler() {
              System.out.println("UserProxy02 的前置處理。。。");
          }
      }

      驗證代碼:

      package testMain;
      
              import org.springframework.context.ApplicationContext;
              import org.springframework.context.support.ClassPathXmlApplicationContext;
              import webPackage.User;
      
      public class Test01 {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("bean01.xml");
      
              User user = (User) context.getBean("user");
              user.add();  //將輸出:UserProxy02 的前置處理。。。  UserProxy 的前置處理。。。  user add...
          }
      }

       

      2.5、完全注解開發(不需要xml配置文件)

      我們可以通過配置類來替代 xml 配置文件,實現完全注解開發:

      照著上面的例子,先建一個 User 類和一個增強類 UserProxy,然后用配置類替代 xml 配置文件。配置類如下:

      package webPackage;
      
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.EnableAspectJAutoProxy;
      
      @Configuration
      @ComponentScan(basePackages = {"testMain", "service", "dao", "webPackage"})
      @EnableAspectJAutoProxy(proxyTargetClass = true)
      public class AopConfig {
      }

      Spring的 IOC 容器看到 @EnableAspectJAutoProxy 注解,就會自動查找帶有@Aspect的Bean,然后根據每個方法的@Before@Around等注解把AOP注入到特定的Bean中。

      使用 bean 跟用配置文件方式不太一樣,代碼如下:

      package testMain;
      
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import webPackage.AopConfig;
      import webPackage.User;
      
      public class Test01 {
          public static void main(String[] args) {
              AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
              User user = (User) context.getBean("user");
              user.add();
          }
      }

       

      2.6、直接通過配置文件實現AOP(一般不用)

      先創建一個類:

      然后創建增強類:

      配置前置通知:

       

      posted @ 2021-04-27 23:59  wenxuehai  閱讀(509)  評論(0)    收藏  舉報
      //右下角添加目錄
      主站蜘蛛池模板: 久久天天躁综合夜夜黑人鲁色| 张家界市| 日韩大片看一区二区三区| 亚洲熟女精品一区二区| 成全高清在线播放电视剧| 国产精品午夜福利在线观看| 爱色精品视频一区二区| 久久九九精品国产免费看小说| 又黄又无遮挡AAAAA毛片| 人妻系列中文字幕精品| 国产精品午夜福利资源| 九九热在线视频精品免费| 亚洲精品色一区二区三区| 日本一卡2卡3卡4卡无卡免费| 伊人色综合久久天天| 在国产线视频A在线视频| 国产精品中文字幕视频| 国产成人精品中文字幕| 国产精品99精品久久免费| 激情亚洲专区一区二区三区| 林芝县| 国产亚洲精品岁国产精品| 亚洲美免无码中文字幕在线| 国产普通话刺激视频在线播放| 欧美成本人视频免费播放| 国产盗摄xxxx视频xxxx| 92国产精品午夜福利免费| 亚洲色大成网站www永久男同| 亚洲产国偷v产偷v自拍色戒| 国产精品露脸视频观看| 日韩精品一区二区在线看| 撕开奶罩揉吮奶头视频| 无码人妻出轨黑人中文字幕| 亚洲综合小综合中文字幕| 老熟妇性老熟妇性色| 亚洲区一区二区三区精品| 久久综合伊人77777| 中文乱码人妻系列一区二区| 亚洲美女厕所偷拍美女尿尿| 精品视频不卡免费观看| 鲁山县|