最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring AOP使用之多切面運(yùn)行順序

 更新時(shí)間:2022年02月14日 12:02:32   作者:起個(gè)名字都這么男  
這篇文章主要介紹了Spring AOP使用之多切面運(yùn)行順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Spring AOP多切面運(yùn)行順序

多切面運(yùn)行順序

當(dāng)一個(gè)方法的執(zhí)行被多個(gè)切面共同切的時(shí)候,環(huán)繞通知只影響當(dāng)前切面的通知順序,例如創(chuàng)建兩個(gè)切面logUtil,validateUtil兩個(gè)切面共同監(jiān)視計(jì)算器類的加法運(yùn)算,add(int a,int b);測(cè)試中,看切面工具類的名稱首字母,默認(rèn)情況下a-z執(zhí)行順序,所以這個(gè)時(shí)候logUtil切面通知比validateUtil先執(zhí)行通知;

所以順序是:L的前置通知 -->v的前置通知–>執(zhí)行add方法,然后v的后置通知–>V的后置返回–>L的后置通知–>L的后置返回。

但是當(dāng)logUtil中加入了環(huán)繞通知,所以環(huán)繞通知要比logUtil的普通通知先執(zhí)行,環(huán)繞通知功能很強(qiáng)大,在通過反射執(zhí)行方法的前面我們可以更改這個(gè)方法的參數(shù),但是普通通知不能這么做。雖然在logUtil加了環(huán)繞通知,但是這個(gè)環(huán)繞通知只是比logUtil的普通通知先執(zhí)行無論是進(jìn)入切面前還是出切面時(shí),他并不影響validateUtil這個(gè)切面的普通通知的執(zhí)行順序,所以加了環(huán)繞通知執(zhí)行順序是

環(huán)繞前置–> log前置–>va前置–>目標(biāo)方法–>va后置–>va返回–>環(huán)繞返回通知–>環(huán)繞后置–>log后置–>log返回。

圖:

這里的validate切面就是圖中的VaAspect;

對(duì)啦,可以更改默認(rèn)的切面順序,要在將要更改的切面類上加入@order(int value)注解,value默認(rèn)值很大,超級(jí)大,越大執(zhí)行的優(yōu)先級(jí)越低,所以如果把它調(diào)成1就是先執(zhí)行這個(gè)切面的通知。

AOP的應(yīng)用場(chǎng)景

  • aop可以進(jìn)行日志記錄;
  • aop可以做權(quán)限驗(yàn)證
  • AOP可以做安全檢查
  • AOP可以做事務(wù)控制

回憶基于注解的AOC配置

  • 將目標(biāo)類和切面類都加入到IOC容器中。@Component
  • 告訴Spring哪個(gè)是切面類@Aspect
  • 在切面類中使用五個(gè)通知注解來配置切面中的這些方法都什么時(shí)候在那運(yùn)行
  • 開啟注解的aop功能。

不使用注解實(shí)現(xiàn)AOP配置。

1.切面類

public class LogUtil {
    public void performance(){}
    public void logStart(JoinPoint joinPoint)
    {
        //獲取方法上的參數(shù)列表
        Object[] args = joinPoint.getArgs();
        //獲取方法簽名
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();//獲取方法名
        System.out.println("前置通知:"+name+" 方法開始執(zhí)行了....參數(shù)是:"+ Arrays.asList(args) +"");
    }
    public void logReturn(JoinPoint point,Object result)
    {
        String name = point.getSignature().getName();
        Object[] args = point.getArgs();
        System.out.println("返回通知: "+name+"方法正常執(zhí)行,返回結(jié)果是:"+result+"");
    }
    public void logException(JoinPoint point,Exception e)
    {
        String name = point.getSignature().getName();
        System.out.println("異常通知:"+name+" 方法出現(xiàn)了異常,異常是 "+e+"...");
    }
    public void logEnd(JoinPoint joinPoint)
    {
        String name = joinPoint.getSignature().getName();
        System.out.println("后置通知:"+name+"方法結(jié)束了");
    }
    //環(huán)繞通知
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint){
        Object proceed = null;
            //獲取方法名
        String name = proceedingJoinPoint.getSignature().getName();
            //獲取執(zhí)行方法的參數(shù)列表
        Object[] args = proceedingJoinPoint.getArgs();
        try {
            System.out.println("環(huán)繞前置通知:"+name+"方法開始執(zhí)行了,參數(shù)是"+Arrays.asList(args)+"");
            //等于 method.invoke();通過反射執(zhí)行指定方法
            proceed = proceedingJoinPoint.proceed();
            System.out.println("環(huán)繞返回通知:"+name+"方法返回結(jié)果是"+proceed+";");
        } catch (Throwable throwable) {
            System.out.println("環(huán)繞異常通知:異常是"+throwable+"");
            throwable.printStackTrace();
        }finally {
            System.out.println("環(huán)繞后置通知:"+name+"方法結(jié)束了");
        }
        return proceed;
    }

2.被切入的類(這里是一個(gè)計(jì)算器類)

package main.java.cn.zixue.domain;public class MyCalculator
{   
  public int add(int a,int b)   
 {
         return a+b;   
 }    
 public int sub(int a,int b) 
 {        
 	return a-b;    
 }
     public int mul(int a,int b)
 {        
 	return a*b;   
  }    
  public int dev(int a,int b)
  {        
  		return a/b;    
  }    
  public double add(double a,float b,int c) 
  {
          return a+b+c;    
   }
 }

3.配置文件

<?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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="main.java.cn"></context:component-scan>
    <bean id="myCalculator" class="main.java.cn.zixue.domain.MyCalculator"></bean>
    <bean id="logUtil" class="main.java.cn.zixue.utils.LogUtil"></bean>
    <!--AOP名稱空間-->
    <aop:config>
      <!--  制定切面的方法-->
        <aop:pointcut id="performance" expression="execution(public * main.java.cn.zixue.domain.MyCalculator.*(..))"></aop:pointcut>
        <!--指定切面-->
        <aop:aspect ref="logUtil">
            <aop:after method="logEnd" pointcut-ref="performance"></aop:after>
            <aop:before method="logStart" pointcut-ref="performance"></aop:before>
            <aop:after-returning method="logReturn" pointcut-ref="performance" returning="result"></aop:after-returning>
            <aop:after-throwing method="logException" pointcut-ref="performance" throwing="e"></aop:after-throwing>
            <aop:around method="myAround" pointcut-ref="performance"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>

4.測(cè)試結(jié)果

@Test
public void Test02()
{
    MyCalculator myCalculator = (MyCalculator) context.getBean("myCalculator");
    myCalculator.add(1,10);
    System.out.println("========================");
}

前置通知:add 方法開始執(zhí)行了…參數(shù)是:[1, 10]
環(huán)繞前置通知:add方法開始執(zhí)行了,參數(shù)是[1, 10]
環(huán)繞返回通知:add方法返回結(jié)果是11;
環(huán)繞后置通知:add方法結(jié)束了
返回通知: add方法正常執(zhí)行,返回結(jié)果是:11
后置通知:add方法結(jié)束了
====================**

普通前置通知->環(huán)繞通知->環(huán)繞返回->環(huán)繞后置->普通返回->普通后置

注解和配置文件在什么時(shí)候使用?該如何選擇?

注解的優(yōu)點(diǎn):配置快速簡潔。

配置文件的優(yōu)點(diǎn):功能豐富,注解有的他都可以實(shí)現(xiàn),注解沒有的他也有。

當(dāng)遇到重要的切面時(shí),用配置文件寫,例如權(quán)限驗(yàn)證及管理。對(duì)于常用的普通的切面就用注解。

Spring AOP切面執(zhí)行順序和常見問題

切面注解的執(zhí)行順序

public Object aop(Method method,Object object) {
    try {
        try {
            /*doAround start*/
            doBefore();
            method.invoke(object);
            /*doAround end*/
        } finally {
            doAfter();
        }
        doAfterReturning();
    } catch (Exception e) {
        doAfterThrowing();
    }
}

切面間的執(zhí)行順序

切面之間使用older注解,區(qū)分調(diào)用順序,Order值越小,那么切面越先執(zhí)行(越后結(jié)束).

不指定Order,那么Order是默認(rèn)值->Integer.MAX_VALUE. 如果Order相同,則是按照切面字母的順序來執(zhí)行切面.比如@Transactional和@Cacheable->對(duì)應(yīng)的切面是TransactionInterceptor和CacheInterceptor,則先執(zhí)行@Cacheable的切面

@Transactional也是通過切面實(shí)現(xiàn),Order值是Integer.MAX_VALUE。(如果在service方法上同時(shí)添加帶older的日志注解,在日志切面after里面報(bào)錯(cuò),不會(huì)回滾事務(wù))

常見問題示例

1.方法A調(diào)用同類中的方法B,方法B上的切面不會(huì)生效

問題示例:

@Component 
public class StrategyService extends BaseStrategyService  { 
    public PricingResponse getFactor(Map<String, String> pricingParams) { 
        // 做一些參數(shù)校驗(yàn),以及異常捕獲相關(guān)的事情 
        return this.loadFactor(tieredPricingParams); 
    }
 
    @Override 
    @StrategyCache(keyName = "key0001", expireTime = 60 * 60 * 2) 
    private PricingResponse loadFactor(Map<String, String> pricingParams) { 
        //代碼執(zhí)行 
    } 
}
 

原因:Spring的AOP是通過代理對(duì)象調(diào)用,只有這種調(diào)用方式,才能夠在真正的對(duì)象的執(zhí)行前后,能夠讓代理對(duì)象也執(zhí)行相關(guān)代碼,才能起到切面的作用。而對(duì)于上面使用this的方式調(diào)用,這種只是自調(diào)用,并不會(huì)使用代理對(duì)象進(jìn)行調(diào)用,也就無法執(zhí)行切面類。

 public static void main(String[] args) { 
        ProxyFactory factory = new ProxyFactory(new SimplePojo()); 
        factory.addInterface(Pojo.class); 
        factory.addAdvice(new RetryAdvice()); 
        Pojo pojo = (Pojo) factory.getProxy(); 
        // this is a method call on the proxy! 
        pojo.foo(); 
    }

解決方法:使用AopContext.currentProxy()獲取到代理對(duì)象,然后通過代理對(duì)象調(diào)用對(duì)應(yīng)的方法。還有個(gè)地方需要注意,以上方式還需要將Aspect的expose-proxy設(shè)置成true。

@Component 
public class StrategyService{ 
    public PricingResponse getFactor(Map<String, String> pricingParams) { 
        // 做一些參數(shù)校驗(yàn),以及異常捕獲相關(guān)的事情 
        // 這里不使用this.loadFactor而是使用AopContext.currentProxy()調(diào)用,目的是解決AOP代理不支持方法自調(diào)用的問題 
        if (AopContext.currentProxy() instanceof StrategyService) { 
            return ((StrategyService)AopContext.currentProxy()).loadFactor(tieredPricingParams); 
        } else {
 
            // 部分實(shí)現(xiàn)沒有被代理過,則直接進(jìn)行自調(diào)用即可 
            return loadFactor(tieredPricingParams); 
        } 
    }
 
    @Override 
    @StrategyCache(keyName = "key0001", expireTime = 60 * 60 * 2) 
    private PricingResponse loadFactor(Map<String, String> oricingParams) { 
        //代碼執(zhí)行 
    } 
}
 
//還有個(gè)地方需要注意,以上方式還需要將Aspect的expose-proxy設(shè)置成true。如果是配置文件修改:
 <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
//如果是SpringBoot,則修改應(yīng)用啟動(dòng)入口類的注解:
@EnableAspectJAutoProxy(exposeProxy = true) 
public class Application { 
} 
 

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java保留兩位小數(shù)的幾種寫法總結(jié)

    Java保留兩位小數(shù)的幾種寫法總結(jié)

    相信大家在平時(shí)做項(xiàng)目時(shí),可能會(huì)有這樣的業(yè)務(wù)需求: 頁面或界面上展示的數(shù)據(jù)保留小數(shù)點(diǎn)后兩位。 那么這篇文章小編就和大家分享了利用Java保留兩位小數(shù)的幾種寫法,文章給出了詳細(xì)的示例代碼,對(duì)大家的學(xué)習(xí)和理解很有幫助,有需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)下吧。
    2016-11-11
  • java將一個(gè)目錄下的所有數(shù)據(jù)復(fù)制到另一個(gè)目錄下

    java將一個(gè)目錄下的所有數(shù)據(jù)復(fù)制到另一個(gè)目錄下

    這篇文章主要為大家詳細(xì)介紹了java將一個(gè)目錄下的所有數(shù)據(jù)復(fù)制到另一個(gè)目錄下,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • SpringBoot 如何編寫配置文件

    SpringBoot 如何編寫配置文件

    這篇文章主要介紹了SpringBoot 編寫配置文件的兩種方法,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下
    2020-11-11
  • SpringBoot實(shí)現(xiàn)接口數(shù)據(jù)的加解密功能

    SpringBoot實(shí)現(xiàn)接口數(shù)據(jù)的加解密功能

    這篇文章主要介紹了SpringBoot實(shí)現(xiàn)接口數(shù)據(jù)的加解密功能,對(duì)接口的加密解密操作主要有兩種實(shí)現(xiàn)方式,文中給大家詳細(xì)介紹,需要的朋友可以參考下
    2019-10-10
  • Java開發(fā)之ssm三大框架整合

    Java開發(fā)之ssm三大框架整合

    SSM框架是spring?MVC?,spring和mybatis框架的整合,是標(biāo)準(zhǔn)的MVC模式,將整個(gè)系統(tǒng)劃分為表現(xiàn)層,controller層,service層,DAO層四層,使用spring?MVC負(fù)責(zé)請(qǐng)求的轉(zhuǎn)發(fā)和視圖管理,spring實(shí)現(xiàn)業(yè)務(wù)對(duì)象管理,mybatis作為數(shù)據(jù)對(duì)象的持久化引擎
    2022-05-05
  • SpringSecurity退出功能實(shí)現(xiàn)的正確方式(推薦)

    SpringSecurity退出功能實(shí)現(xiàn)的正確方式(推薦)

    本文將介紹在Spring Security框架下如何實(shí)現(xiàn)用戶的"退出"logout的功能。本文通過實(shí)例代碼講解的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2019-11-11
  • Java開發(fā)深入分析講解二叉樹的遞歸和非遞歸遍歷方法

    Java開發(fā)深入分析講解二叉樹的遞歸和非遞歸遍歷方法

    樹是一種重要的非線性數(shù)據(jù)結(jié)構(gòu),直觀地看,它是數(shù)據(jù)元素(在樹中稱為結(jié)點(diǎn))按分支關(guān)系組織起來的結(jié)構(gòu),很象自然界中的樹那樣。樹結(jié)構(gòu)在客觀世界中廣泛存在,如人類社會(huì)的族譜和各種社會(huì)組織機(jī)構(gòu)都可用樹形象表示,本篇介紹二叉樹的遞歸與非遞歸遍歷的方法
    2022-05-05
  • java實(shí)現(xiàn)將漢語轉(zhuǎn)換為拼音功能

    java實(shí)現(xiàn)將漢語轉(zhuǎn)換為拼音功能

    這篇文章主要介紹了java實(shí)現(xiàn)將漢語轉(zhuǎn)換為拼音功能,非常不錯(cuò),具有參考借鑒價(jià)值 ,需要的朋友可以參考下
    2017-05-05
  • 詳解Spring Security的formLogin登錄認(rèn)證模式

    詳解Spring Security的formLogin登錄認(rèn)證模式

    對(duì)于一個(gè)完整的應(yīng)用系統(tǒng),與登錄驗(yàn)證相關(guān)的頁面都是高度定制化的,非常美觀而且提供多種登錄方式。這就需要Spring Security支持我們自己定制登錄頁面,也就是本文給大家介紹的formLogin模式登錄認(rèn)證模式,感興趣的朋友跟隨小編一起看看吧
    2019-11-11
  • SpringBoot集成SpringSecurity和JWT做登陸鑒權(quán)的實(shí)現(xiàn)

    SpringBoot集成SpringSecurity和JWT做登陸鑒權(quán)的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot集成SpringSecurity和JWT做登陸鑒權(quán)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04

最新評(píng)論

岐山县| 南部县| 繁峙县| 香河县| 阿拉善右旗| 上虞市| 东平县| 万全县| 开阳县| 长宁区| 乌恰县| 崇义县| 富民县| 琼中| 连南| 中超| 汤阴县| 桑日县| 青浦区| 东宁县| 麻城市| 云浮市| 彭阳县| 乌恰县| 长沙县| 梁山县| 东乌珠穆沁旗| 鄂尔多斯市| 云和县| 福鼎市| 呼和浩特市| 交口县| 东乡| 大足县| 砚山县| 永定县| 连山| 大同市| 璧山县| 习水县| 新和县|