欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring基礎(chǔ)之AOP的概念介紹

 更新時(shí)間:2022年06月12日 07:49:29   作者:御狐神  
AOP是Spring的關(guān)鍵特性之一,雖然Spring的IOC特性并不依賴于AOP,本文重點(diǎn)介紹AOP編程中的一些術(shù)語(yǔ),這些術(shù)語(yǔ)不僅僅局限于Spring,它適用于所有的AOP編程,感興趣的朋友一起看看吧

Spring容器包含兩個(gè)重要的特性:面向切面編程(AOP)和控制反轉(zhuǎn)(IOC)。面向切面編程是面向?qū)ο螅∣OP)的一種補(bǔ)充,在面向?qū)ο缶幊痰倪^(guò)程中編程針對(duì)的目標(biāo)是一個(gè)個(gè)對(duì)象,而面向切面編程中編程針對(duì)的目標(biāo)是一個(gè)個(gè)切面。切面支持跨類型跨對(duì)象(如事務(wù)的切面可以加在任何地方)進(jìn)行模塊化。

前言

AOP是Spring的關(guān)鍵特性之一,雖然Spring的IOC特性并不依賴于AOP(意味著你可以只使用Spring的IOC特性而不使用AOP特性),但是二者結(jié)合起來(lái)可以靈活的實(shí)現(xiàn)很多中間件解決方案。比如我們經(jīng)常使用的事務(wù)(@Transaction),就是通過(guò)AOP方案實(shí)現(xiàn)的。本文重點(diǎn)介紹AOP編程中的一些術(shù)語(yǔ),這些術(shù)語(yǔ)不僅僅局限于Spring,它適用于所有的AOP編程。

  • 切面(Aspect):面向切面編程可以跨類跨對(duì)象進(jìn)行切面編程,一個(gè)切面就是對(duì)一類橫切關(guān)注點(diǎn)的模塊化。
  • 切入點(diǎn)(JoinPoint):程序執(zhí)行過(guò)程中的一個(gè)點(diǎn),如方法調(diào)用、字段訪問(wèn)和異常拋出等。
  • 增強(qiáng)(Advice):用于對(duì)切面增強(qiáng),包含前增強(qiáng)、后增強(qiáng)和環(huán)繞增強(qiáng)。大多數(shù)AOP框架會(huì)對(duì)切入點(diǎn)進(jìn)行攔截,并在切入點(diǎn)維護(hù)一個(gè)攔截器鏈。
  • 目標(biāo)對(duì)象(TargetObject):包含一個(gè)或者多個(gè)切面的對(duì)象。
  • AOP代理(AOPProxy):通過(guò)Java動(dòng)態(tài)代理或者CGLib增強(qiáng)得到的代理對(duì)象。
  • 織入(Weaving):將切面整合到完整的流執(zhí)行流程。

Spring的AOP的功能和目標(biāo)

Spring的AOP使用純Java語(yǔ)言實(shí)現(xiàn)(如AspectJ就不是Java語(yǔ)言),不需要任何額外的編譯流程,不需要修改類加載器,適用于任何Servlet容器和應(yīng)用服務(wù)。Spring的AOP只支持方法攔截,不支持字段攔截,如果用戶需要使用字段攔截,可以考慮引入AspectJ等類似的框架。

Spring的AOP框架和其它的框架有些不同,Spring的Aop框架不僅僅是為了提供一個(gè)AOP功能,它更重要的功能是和Spring的IOC容器結(jié)合,提供一些企業(yè)應(yīng)用服務(wù)的解決方案(如事務(wù)等),我們可以和定義一個(gè)普通Bean一樣的方式去定以一個(gè)切面。Spring的AOP不支持非常細(xì)粒度的AOP,只支持對(duì)容器中的Bean進(jìn)行AOP,如果需要更細(xì)粒度的AOP,可以考慮使用AspectJ。Spring容器的一個(gè)優(yōu)秀的特性就是非侵入性,所以你可以靈活的選擇自己的AOP方案,不一定非要使用Spring的方案。

代理方式

Spring對(duì)實(shí)現(xiàn)接口的方法默認(rèn)使用Java動(dòng)態(tài)代理實(shí)現(xiàn)AOP攔截,對(duì)于非接口方法則會(huì)使用CGLIB字節(jié)碼工具實(shí)現(xiàn)代理。

@AspectJ的支持

@AspectJ注解可以把一個(gè)普通的Java類聲明為切面。@AspectJ注解是AspectJ5引入的注解,Spring雖然可以讀取AspectJ5的注解用于切面元數(shù)據(jù)的配置,但是在運(yùn)行的時(shí)候使用的仍然是Spring AOP進(jìn)行代理,而沒(méi)有使用AspectJ的編譯器或者織入邏輯。我們會(huì)在后續(xù)討論如何在Spring中使用AspectJ的編譯器和織入邏輯。

啟用@AspectJ

Spring默認(rèn)沒(méi)有啟用AspectJ,如果你需要Spring支持@AspectJ注解對(duì)應(yīng)的切面,可以通過(guò)在配置類上添加注解或者使用XML啟用配置(AspectJ所在的包是:aspectjweaver.jar)。

通過(guò)Java注解啟用AspectJ注解支持:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}

通過(guò)XML配置啟用AspectJ注解

<aop:aspectj-autoproxy/>

定義一個(gè)切面

當(dāng)啟用AspectJ支持之后,開(kāi)發(fā)者定義的任何Aspect切面會(huì)自動(dòng)地被檢測(cè)到,然后Spring AOP會(huì)對(duì)切面進(jìn)行攔截。下面兩個(gè)例子展示了如何配置AspectJ切面,你可以通過(guò)添加@Component注解把切面Bean注冊(cè)到Spring容器中。

<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect">
    <!-- configure properties of the aspect here -->
</bean>
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {

}

聲明一個(gè)切入點(diǎn)

切入點(diǎn)程序運(yùn)行過(guò)程中我們感興趣的一個(gè)點(diǎn),Spring的AOP框架只支持發(fā)現(xiàn)對(duì)Spring Bean方法上的切入點(diǎn),因此你可以簡(jiǎn)單的把切入點(diǎn)理解為SpringBean的方法。

切入點(diǎn)確定感興趣的連接點(diǎn),從而使我們能夠控制何時(shí)運(yùn)行通知。springaop只支持springbean的方法執(zhí)行連接點(diǎn),因此可以將切入點(diǎn)看作與springbean上方法的執(zhí)行相匹配。切入點(diǎn)聲明由兩部分組成:一部分是由名稱和任何參數(shù)組成的簽名,另一部分是確定我們感興趣的方法執(zhí)行的切入點(diǎn)表達(dá)式。在AOP的@AspectJ注釋樣式中,切入點(diǎn)簽名由常規(guī)方法定義提供,切入點(diǎn)表達(dá)式由@pointcut注釋指示(用作切入點(diǎn)簽名的方法必須具有void返回類型)。切入點(diǎn)由兩部分組成,一部分是用于區(qū)別不同切入點(diǎn)的標(biāo)識(shí)(下面例子中的 private void anyOldTransfer() {} )),另外一部分是確定我們感興趣的Bean方法的表達(dá)式(下面例子中的 @Pointcut("execution(* transfer(..))") ), 下面的例子展示了一個(gè)切入點(diǎn)的定義:

@Pointcut("execution(* transfer(..))") // the pointcut expression
private void anyOldTransfer() {} // the pointcut signature

Spring匹配切入點(diǎn)的語(yǔ)法使用了AspectJ5中的表達(dá)式語(yǔ)法,我們可以參考AspectJ文檔相關(guān)的語(yǔ)法.

常見(jiàn)的切入點(diǎn)匹配表達(dá)

Spring支持下面常見(jiàn)的AspectJ切面定義語(yǔ)法:

  • execution:用于匹配方法的連接點(diǎn)。
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}
  • within:用于匹配類型內(nèi)的方法。
@Pointcut("within(com.xyz.myapp.trading..*)")
private void inTrading() {}
  • this:匹配當(dāng)前AOP代理對(duì)象的執(zhí)行方法
@target(org.springframework.transaction.annotation.Transactional)
  • target:target匹配目標(biāo)對(duì)象的類型,即被代理對(duì)象的類型,例如A繼承了B接口,則使用target("B"),target("A")均可以匹配到A
//    當(dāng)前AOP對(duì)象實(shí)現(xiàn)了 IPointcutService接口的任何方法
@Pointcut("target(cn.javass.spring.chapter6.service.IPointcutService)")
private void anyPublicOperation() {}
  • args:用于限定切點(diǎn)方法的參數(shù)類型。
args(java.io.Serializable)
  • @target:被代理對(duì)象應(yīng)該包含指定的注解。
@target(org.springframework.transaction.annotation.Transactional)
  • @args: 被代理對(duì)象的參數(shù)包含指定的注解。
@args(com.xyz.security.Classified)
  • @within: 被代理的對(duì)象應(yīng)包含指定注解
@within(org.springframework.transaction.annotation.Transactional)
  • @annotation:切入點(diǎn)包含指定的注解。
@annotation(org.springframework.transaction.annotation.Transactional)

我們可以通過(guò)“&&”和“||”對(duì)多個(gè)條件進(jìn)行組合,AspectJ還有很多其它的表達(dá)式,但是Spring不支持除上述表達(dá)式以外的其它表達(dá)式。AspectJ其它表達(dá)式包含: call, get, set, preinitialization, staticinitialization, initialization, handler, adviceexecution, withincode, cflow, cflowbelow, if, @this, @withincode等。

我們?cè)谑褂肧pring的代理方法之前,應(yīng)該知道其代理原理。Java動(dòng)態(tài)代理只能攔截public接口方法上的調(diào)用,CGLib只能攔截public、protected和defult方法。如果你需要更深層次的攔截,可以考慮使用底層的Aspectj。

切面的增強(qiáng)

我們?cè)谏厦娴牟襟E定義好了一個(gè)切入點(diǎn),我們現(xiàn)在就可以對(duì)這個(gè)切入點(diǎn)進(jìn)行額外操作,這些額外操作被稱為增強(qiáng),Spring支持四種增強(qiáng)方式:前增強(qiáng)、后增強(qiáng)、異常增強(qiáng)和環(huán)繞增強(qiáng)。Spring支持在增強(qiáng)方法的定義上直接定義切入點(diǎn)。

前增強(qiáng)BeforeAdvice

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
    @Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
    public void doAccessCheck() {
        // ...
    }
}
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {

    @Before("execution(* com.xyz.myapp.dao.*.*(..))")
    public void doAccessCheck() {
        // ...
    }
}

后增強(qiáng)

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
    @AfterReturning(
        pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()",
        returning="retVal")
    public void doAccessCheck(Object retVal) {
        // ...
    }
}

異常增強(qiáng)

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
    @AfterThrowing(
        pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()",
        throwing="ex")
    public void doRecoveryActions(DataAccessException ex) {
        // ...
    }
}

環(huán)繞增強(qiáng)

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
    @Around("com.xyz.myapp.CommonPointcuts.businessService()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }
}

代理機(jī)制

我們前面說(shuō)過(guò),Spring AOP通過(guò)動(dòng)態(tài)代理和CGLIB實(shí)現(xiàn)AOP對(duì)象的代理。我們可以通過(guò)如下配置設(shè)置動(dòng)態(tài)代理全部走CGLIB。

<aop:config proxy-target-class="true">
    <!-- other beans defined here... -->
</aop:config>

代理工廠的使用

Spring AOP實(shí)現(xiàn)代理的核心類是 AspectJProxyFactory ,我們可以使用這個(gè)類編程式生成代理對(duì)象:

// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);

// add an aspect, the class must be an @AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);

// you can also add existing aspect instances, the type of the object supplied must be an @AspectJ aspect
factory.addAspect(usageTracker);

// now get the proxy object...
MyInterfaceType proxy = factory.getProxy()

到此這篇關(guān)于Spring基礎(chǔ)之AOP的概念介紹的文章就介紹到這了,更多相關(guān)spring aop概念內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringMVC文件上傳中要解決的問(wèn)題大匯總

    SpringMVC文件上傳中要解決的問(wèn)題大匯總

    這篇文章主要介紹了SpringMVC文件上傳中要解決的問(wèn)題,主要有中文文件名編碼問(wèn)題,文件位置存儲(chǔ)問(wèn)題以及文件名沖突問(wèn)題等等,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • java 中用split分割字符串,最后的空格等不被拆分的方法

    java 中用split分割字符串,最后的空格等不被拆分的方法

    下面小編就為大家?guī)?lái)一篇java 中用split分割字符串,最后的空格等不被拆分的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • Spring系列之事物管理

    Spring系列之事物管理

    這篇文章主要介紹了Spring系列之事物管理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring方面知識(shí)具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們一起學(xué)習(xí)學(xué)習(xí)吧
    2021-09-09
  • java代碼之謎運(yùn)算符篇

    java代碼之謎運(yùn)算符篇

    從最簡(jiǎn)單的運(yùn)算符加號(hào)(+)說(shuō)起,加號(hào)(+)是個(gè)二元運(yùn)算符——也就是說(shuō),加號(hào)只把兩個(gè)數(shù)聯(lián)接起來(lái),從來(lái)不把第三個(gè)或者更多的聯(lián)接起來(lái)
    2012-11-11
  • Java連接 JDBC基礎(chǔ)知識(shí)(操作數(shù)據(jù)庫(kù):增刪改查)

    Java連接 JDBC基礎(chǔ)知識(shí)(操作數(shù)據(jù)庫(kù):增刪改查)

    這篇文章主要介紹了Java連接 JDBC基礎(chǔ)知識(shí),包括操作數(shù)據(jù)庫(kù)之增刪改查操作,需要的朋友可以參考下
    2021-04-04
  • Spring JPA配置文件Eclipse報(bào)錯(cuò)如何解決

    Spring JPA配置文件Eclipse報(bào)錯(cuò)如何解決

    這篇文章主要介紹了Spring JPA配置文件Eclipse報(bào)錯(cuò)如何解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Java Swing實(shí)現(xiàn)坦克大戰(zhàn)游戲

    Java Swing實(shí)現(xiàn)坦克大戰(zhàn)游戲

    這篇文章主要介紹了Java Swing實(shí)現(xiàn)坦克大戰(zhàn)游戲,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很大的幫助喲,需要的朋友可以參考下
    2021-05-05
  • 淺談Java中的四種引用方式的區(qū)別

    淺談Java中的四種引用方式的區(qū)別

    下面小編就為大家?guī)?lái)一篇淺談Java中的四種引用方式的區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-09-09
  • 關(guān)于java中構(gòu)造函數(shù)的一些知識(shí)詳解

    關(guān)于java中構(gòu)造函數(shù)的一些知識(shí)詳解

    下面小編就為大家?guī)?lái)一篇關(guān)于java中構(gòu)造函數(shù)的一些知識(shí)詳解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-12-12
  • IDEA maven上傳速度很慢的解決辦法

    IDEA maven上傳速度很慢的解決辦法

    maven上傳的速度很慢,排除網(wǎng)絡(luò)原因,需要檢查配置,本文主要介紹了IDEA maven上傳速度很慢的解決辦法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08

最新評(píng)論