天天看點

spring_Aop

一 AOP

1.1 什麼是AOP

​ AOP 面向切面程式設計。利用AOP可以對業務邏輯的各個部分進行隔離,進而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。

1.2 AOP底層實作

​ 實際上,AOP 的底層是通過 Spring 提供的的動态代理技術實作的。在運作期間,Spring通過動态代理技術動态的生成代理對象,代理對象方法執行時進行增強功能的介入,在去調用目标對象的方法,進而完成功能的增強。

​ Spring 架構監控切入點方法的執行。一旦監控到切入點方法被運作,使用代理機制,動态建立目标對象的代理對象,根據通知類别,在代理對象的對應位置,将通知對應的功能織入,完成完整的代碼邏輯運作。

​ 在 Spring 中,架構會根據目标類是否實作了接口來決定采用哪種動态代理的方式。

  1. ​ 當bean實作接口時,會用JDK代理模式
  2. ​ 當bean沒有實作接口,用cglib實作( 可以強制使用cglib(在spring配置中加入<aop:aspect jautoproxy proxyt-target-class=”true”/>)

1.3 AOP相關術語

* Target(目标對象):代理的目标對象 

* Proxy (代理):一個類被 AOP 織入增強後,就産生一個結果代理類

* Joinpoint(連接配接點):所謂連接配接點是指那些可以被攔截到的點。在spring中,這些點指的是方法,因為 spring隻支援方法類型的連接配接點

* Pointcut(切入點):所謂切入點是指我們要對哪些 Joinpoint 進行攔截的定義 

* Advice(通知/ 增強):所謂通知是指攔截到 Joinpoint 之後所要做的事情就是通知 分類:前置通知、後置通知、異常通知、最終通知、環繞通知
* Aspect(切面):是切入點和通知(引介)的結合 

* Weaving(織入):是指把增強應用到目标對象來建立新的代理對象的過程。spring采用動态代理織 入,而AspectJ采用編譯期織入和類裝載期織入
           
1. 編寫核心業務代碼(目标類的目标方法) 切入點
2. 把公用代碼抽取出來,制作成通知(增強功能方法) 通知
3. 在配置檔案中,聲明切入點與通知間的關系,即切面
           

1.3 基于(xml)AOP開發

  1. 建立java項目,導入AOP相關坐标
<dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.15</version>
        </dependency>
    <!--導入spring的context坐标,context依賴aop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
    <!-- aspectj的織入(切點表達式需要用到該jar包) -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    <!--spring整合junit-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
    </dependencies>

           
  1. 建立目标接口和目标實作類(定義切入點)(略)
  2. 建立通知類及方法(定義通知) (略)
  3. 将目标類和通知類對象建立權交給spring (略)
  4. 在核心配置檔案中配置織入關系,及切面
<?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: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.xsd">


    <!--目标類交給IOC容器-->
    <bean id="accountServcie" class="com.lagou.servlet.impl.AccountServiceImpl"></bean>

    <!--通知類交給IOC容器-->
    <bean id="myAdvice" class="com.lagou.advice.MyAdvice"></bean>

    <!--AOP配置-->
    <aop:config>
        <!--抽取的切點表達式-->
        <aop:pointcut id="myPointcut" expression="execution(* com.lagou.servlet.impl.AccountServiceImpl.*(..))"/>

        <!--配置切面:切入點+通知-->
        <aop:aspect ref="myAdvice">
       <!--     <aop:before method="before" pointcut-ref="myPointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
            <aop:after method="after" pointcut-ref="myPointcut"/>-->
            <aop:around method="around" pointcut-ref="myPointcut"/>

        </aop:aspect>

    </aop:config>

           

6.編寫測試代碼(略)

1.4 切點表達式

​ 表達式文法:

execution([修飾符] 傳回值類型 包名.類名.方法名(參數))
        execution(public void com.lagou.servlet.impl.AccountServiceImpl.transfer(java.lang.String))

        - 通路修飾符可以省略
        execution(void com.lagou.servlet.impl.AccountServiceImpl.transfer(java.lang.String))

        - 傳回值類型、包名、類名、方法名可以使用星号 * 代替,代表任意
        execution(* *.*.*.*.*.*())

        - 包名與類名之間一個點 . 代表目前包下的類,兩個點 .. 表示目前包及其子包下的類
        execution(* *..*.*())

        - 參數清單可以使用兩個點 .. 表示任意個數,任意類型的參數清單
        execution(* *..*.*(..))

           

通路修飾符可以省略

傳回值類型、包名、類名、方法名可以使用星号 * 代替,代表任意

包名與類名之間一個點 . 代表目前包下的類,兩個點 … 表示目前包及其子包下的類

參數清單可以使用兩個點 … 表示任意個數,任意類型的參數清單

​ 切點表達式抽取 :

<!--AOP配置-->
    <aop:config>
        <!--抽取的切點表達式-->
        <aop:pointcut id="myPointcut" expression="execution(* com.lagou.servlet.impl.AccountServiceImpl.*(..))"/>

        <!--配置切面:切入點+通知-->
        <aop:aspect ref="myAdvice">
       <!--     <aop:before method="before" pointcut-ref="myPointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
            <aop:after method="after" pointcut-ref="myPointcut"/>-->
            <aop:around method="around" pointcut-ref="myPointcut"/>

        </aop:aspect>
</aop:config>
           

1.5 通知類型

spring_Aop

1.6 基于注解的AOP開發

  1. 建立java項目,導入AOP相關坐标 (略)
  2. 建立目标接口和目标實作類(定義切入點) (略)
  3. 建立通知類(定義通知) (略)
  4. 将目标類和通知類對象建立權交給spring (略)
  5. 在通知類中使用注解配置織入關系,更新為切面類
@Component 
@Aspect //更新為切面類,配置切入點和通知關系
public class MyAdvice {
    @Before("execution(* com.lagou..*.*(..))")
        public void before() { 
        System.out.println("前置通知..."); 
    } 
}
           
  1. 在配置檔案中開啟元件掃描和 AOP 的自動代理
<!--元件掃描--> 
<context:component-scan base-package="com.lagou"/>

<!--aop的自動代理--> 
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>


           
  1. 編寫測試代碼 (略)

1.8 通知類型

spring_Aop

環繞通知:

​ proceedingJoinPoint.該接口有一個方法proceed()此方法就相當于明确調用切入點方法.

​ 該接口可以作為環繞通知的方法參數,在程式執行時,Spring架構會為我們提供該接口的實作類供我們使用

目前四個通知組合在一起時,執行順序如下:

​ @Before -> @After -> @AfterReturning(如果有異常:@AfterThrowing)

注解開啟元件掃描和 AOP 的自動代理

@ComponentScan("com.lagou")
@EnableAspectJAutoProxy //替代 <aop:aspectj-autoproxy />
           

,在程式執行時,Spring架構會為我們提供該接口的實作類供我們使用

目前四個通知組合在一起時,執行順序如下:

​ @Before -> @After -> @AfterReturning(如果有異常:@AfterThrowing)

注解開啟元件掃描和 AOP 的自動代理

@ComponentScan("com.lagou")
@EnableAspectJAutoProxy //替代 <aop:aspectj-autoproxy />