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

解析Spring中面向切面編程

 更新時間:2021年06月11日 11:29:59   作者:SharpCJ  
如果說 IoC 是 Spring 的核心,那么面向切面編程就是 Spring 最為重要的功能之一了,在數(shù)據(jù)庫事務(wù)中切面編程被廣泛使用

一、AOP——另一種編程思想

1.1、什么是 AOP

AOP (Aspect Orient Programming),直譯過來就是 面向切面編程。AOP 是一種編程思想,是面向?qū)ο缶幊蹋∣OP)的一種補充。面向?qū)ο缶幊虒⒊绦虺橄蟪筛鱾€層次的對象,而面向切面編程是將程序抽象成各個切面。

從《Spring實戰(zhàn)(第4版)》圖書中扒了一張圖:

從該圖可以很形象地看出,所謂切面,相當(dāng)于應(yīng)用對象間的橫切點,我們可以將其單獨抽象為單獨的模塊。

1.2、為什么需要 AOP

想象下面的場景,開發(fā)中在多個模塊間有某段重復(fù)的代碼,我們通常是怎么處理的?顯然,沒有人會靠“復(fù)制粘貼”吧。在傳統(tǒng)的面向過程編程中,我們也會將這段代碼,抽象成一個方法,然后在需要的地方分別調(diào)用這個方法,這樣當(dāng)這段代碼需要修改時,我們只需要改變這個方法就可以了。然而需求總是變化的,有一天,新增了一個需求,需要再多出做修改,我們需要再抽象出一個方法,然后再在需要的地方分別調(diào)用這個方法,又或者我們不需要這個方法了,我們還是得刪除掉每一處調(diào)用該方法的地方。實際上涉及到多個地方具有相同的修改的問題我們都可以通過 AOP 來解決。

1.3、AOP 實現(xiàn)分類

AOP 要達到的效果是,保證開發(fā)者不修改源代碼的前提下,去為系統(tǒng)中的業(yè)務(wù)組件添加某種通用功能。AOP 的本質(zhì)是由 AOP 框架修改業(yè)務(wù)組件的多個方法的源代碼,看到這其實應(yīng)該明白了,AOP 其實就是前面一篇文章講的代理模式的典型應(yīng)用。
按照 AOP 框架修改源代碼的時機,可以將其分為兩類:

  • 靜態(tài) AOP 實現(xiàn), AOP 框架在編譯階段對程序源代碼進行修改,生成了靜態(tài)的 AOP 代理類(生成的 *.class 文件已經(jīng)被改掉了,需要使用特定的編譯器),比如 AspectJ。
  • 動態(tài) AOP 實現(xiàn), AOP 框架在運行階段對動態(tài)生成代理對象(在內(nèi)存中以 JDK 動態(tài)代理,或 CGlib 動態(tài)地生成 AOP 代理類),如 SpringAOP。

下面給出常用 AOP 實現(xiàn)比較


如不清楚動態(tài)代理的,可參考我前面的一篇文章,有講解靜態(tài)代理、JDK動態(tài)代理和 CGlib 動態(tài)代理。

二、AOP 術(shù)語

AOP 領(lǐng)域中的特性術(shù)語:

  • 通知(Advice): AOP 框架中的增強處理。通知描述了切面何時執(zhí)行以及如何執(zhí)行增強處理。
  • 連接點(join point): 連接點表示應(yīng)用執(zhí)行過程中能夠插入切面的一個點,這個點可以是方法的調(diào)用、異常的拋出。在 Spring AOP 中,連接點總是方法的調(diào)用。
  • 切點(PointCut): 可以插入增強處理的連接點。
  • 切面(Aspect): 切面是通知和切點的結(jié)合。
  • 引入(Introduction):引入允許我們向現(xiàn)有的類添加新的方法或者屬性。
  • 織入(Weaving): 將增強處理添加到目標(biāo)對象中,并創(chuàng)建一個被增強的對象,這個過程就是織入。

概念看起來總是有點懵,并且上述術(shù)語,不同的參考書籍上翻譯還不一樣,所以需要慢慢在應(yīng)用中理解。

三、初步認(rèn)識 Spring AOP

3.1、Spring AOP 的特點

AOP 框架有很多種,1.3節(jié)中介紹了 AOP 框架的實現(xiàn)方式有可能不同, Spring 中的 AOP 是通過動態(tài)代理實現(xiàn)的。不同的 AOP 框架支持的連接點也有所區(qū)別,例如,AspectJ 和 JBoss,除了支持方法切點,它們還支持字段和構(gòu)造器的連接點。而 Spring AOP 不能攔截對對象字段的修改,也不支持構(gòu)造器連接點,我們無法在 Bean 創(chuàng)建時應(yīng)用通知。

3.2、Spring AOP 的簡單例子

下面先上代碼,對著代碼說比較好說,看下面這個例子:
這個例子是基于gradle創(chuàng)建的,首先 build.gradle 文件添加依賴:

dependencies {
    compile 'org.springframework:spring-context:5.0.6.RELEASE'
}

首先創(chuàng)建一個接口 IBuy.java

package com.sharpcj.aopdemo.test1;

public interface IBuy {
    String buy();
}

Boy 和 Gril 兩個類分別實現(xiàn)了這個接口:

Boy.java

package com.sharpcj.aopdemo.test1;

import org.springframework.stereotype.Component;

@Component
public class Boy implements IBuy {
    @Override
    public String buy() {
        System.out.println("男孩買了一個游戲機");
        return "游戲機";
    }
}

Girl.java

package com.sharpcj.aopdemo.test1;

import org.springframework.stereotype.Component;

@Component
public class Girl implements IBuy {
    @Override
    public String buy() {
        System.out.println("女孩買了一件漂亮的衣服");
        return "衣服";
    }
}

配置文件, AppConfig.java

package com.sharpcj.aopdemo;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackageClasses = {com.sharpcj.aopdemo.test1.IBuy.class})
public class AppConfig {
}

測試類, AppTest.java

package com.sharpcj.aopdemo;

import com.sharpcj.aopdemo.test1.Boy;
import com.sharpcj.aopdemo.test1.Girl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AppTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Boy boy = context.getBean("boy",Boy.class);
        Girl girl = (Girl) context.getBean("girl");
        boy.buy();
        girl.buy();
    }
}

運行結(jié)果:

這里運用SpringIOC里的自動部署?,F(xiàn)在需求改變了,我們需要在男孩和女孩的 buy 方法之前,需要打印出“男孩女孩都買了自己喜歡的東西”。用 Spring AOP 來實現(xiàn)這個需求只需下面幾個步驟:

1、 既然用到 Spring AOP, 首先在 build.gralde 文件中引入相關(guān)依賴:

dependencies {
    compile 'org.springframework:spring-context:5.0.6.RELEASE'
    compile 'org.springframework:spring-aspects:5.0.6.RELEASE'
}

2、 定義一個切面類,BuyAspectJ.java

package com.sharpcj.aopdemo.test1;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuyAspectJ {
    @Before("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void haha(){
        System.out.println("男孩女孩都買自己喜歡的東西");
    }
}

這個類,我們使用了注解 @Component 表明它將作為一個Spring Bean 被裝配,使用注解 @Aspect 表示它是一個切面。

類中只有一個方法 haha 我們使用 @Before 這個注解,表示他將在方法執(zhí)行之前執(zhí)行。關(guān)于這個注解后文再作解釋。

參數(shù)("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))") 聲明了切點,表明在該切面的切點是com.sharpcj.aopdemo.test1.Ibuy這個接口中的buy方法。至于為什么這么寫,下文再解釋。

3、 在配置文件中啟用AOP切面功能

package com.sharpcj.aopdemo;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackageClasses = {com.sharpcj.aopdemo.test1.IBuy.class})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
}

我們在配置文件類增加了@EnableAspectJAutoProxy注解,啟用了 AOP 功能,參數(shù)proxyTargetClass的值設(shè)為了 true 。默認(rèn)值是 false,兩者的區(qū)別下文再解釋。

OK,下面只需測試代碼,運行結(jié)果如下:

我們看到,結(jié)果與我們需求一致,我們并沒有修改 Boy 和 Girl 類的 Buy 方法,也沒有修改測試類的代碼,幾乎是完全無侵入式地實現(xiàn)了需求。這就是 AOP 的“神奇”之處。

四、通過注解配置 Spring AOP

4.1、通過注解聲明切點指示器

Spring AOP 所支持的 AspectJ 切點指示器

在spring中嘗試使用AspectJ其他指示器時,將會拋出IllegalArgumentException異常。

當(dāng)我們查看上面展示的這些spring支持的指示器時,注意只有execution指示器是唯一的執(zhí)行匹配,而其他的指示器都是用于限制匹配的。這說明execution指示器是我們在編寫切點定義時最主要使用的指示器,在此基礎(chǔ)上,我們使用其他指示器來限制所匹配的切點。

下圖的切點表達式表示當(dāng)Instrument的play方法執(zhí)行時會觸發(fā)通知。

我們使用execution指示器選擇Instrument的play方法,方法表達式以 * 號開始,標(biāo)識我們不關(guān)心方法的返回值類型。然后我們指定了全限定類名和方法名。對于方法參數(shù)列表,我們使用 .. 標(biāo)識切點選擇任意的play方法,無論該方法的入?yún)⑹鞘裁础?/p>

多個匹配之間我們可以使用鏈接符 &&、||、!來表示 “且”、“或”、“非”的關(guān)系。但是在使用 XML 文件配置時,這些符號有特殊的含義,所以我們使用 “and”、“or”、“not”來表示。

舉例:

限定該切點僅匹配的包是 com.sharpcj.aopdemo.test1,可以使用

execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..)) && within(com.sharpcj.aopdemo.test1.*)

在切點中選擇 bean,可以使用

execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..)) && bean(girl)

修改 BuyAspectJ.java

package com.sharpcj.aopdemo.test1;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuyAspectJ {
    @Before("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..)) && within(com.sharpcj.aopdemo.test1.*) && bean(girl)")
    public void hehe(){
        System.out.println("男孩女孩都買自己喜歡的東西");
    }
}

此時,切面只會對 Girl.java 這個類生效,執(zhí)行結(jié)果:

細(xì)心的你,可能發(fā)現(xiàn)了,切面中的方法名,已經(jīng)被我悄悄地從haha改成了hehe,絲毫沒有影響結(jié)果,說明方法名沒有影響。和 Spring IOC 中用 java 配置文件裝配 Bean 時,用@Bean 注解修飾的方法名一樣,沒有影響。

4.2、通過注解聲明 5 種通知類型

Spring AOP 中有 5 中通知類型,分別如下:

下面修改切面類:

package com.sharpcj.aopdemo.test1;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuyAspectJ {
    @Before("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void hehe() {
        System.out.println("before ...");
    }

    @After("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void haha() {
        System.out.println("After ...");
    }

    @AfterReturning("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void xixi() {
        System.out.println("AfterReturning ...");
    }

    @Around("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void xxx(ProceedingJoinPoint pj) {
        try {
            System.out.println("Around aaa ...");
            pj.proceed();
            System.out.println("Around bbb ...");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

}

為了方便看效果,我們測試類中,只要 Boy 類:

package com.sharpcj.aopdemo;

import com.sharpcj.aopdemo.test1.Boy;
import com.sharpcj.aopdemo.test1.Girl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AppTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Boy boy = context.getBean("boy",Boy.class);
        Girl girl = (Girl) context.getBean("girl");
        boy.buy();
        // girl.buy();
    }
}

執(zhí)行結(jié)果如下:

結(jié)果顯而易見。指的注意的是 @Around 修飾的環(huán)繞通知類型,是將整個目標(biāo)方法封裝起來了,在使用時,我們傳入了 ProceedingJoinPoint 類型的參數(shù),這個對象是必須要有的,并且需要調(diào)用 ProceedingJoinPoint 的 proceed() 方法。 如果沒有調(diào)用 該方法,執(zhí)行結(jié)果為 :

Around aaa ...

Around bbb ...

After ...

AfterReturning ...

可見,如果不調(diào)用該對象的 proceed() 方法,表示原目標(biāo)方法被阻塞調(diào)用,當(dāng)然也有可能你的實際需求就是這樣。

4.3、通過注解聲明切點表達式

如你看到的,上面我們寫的多個通知使用了相同的切點表達式,對于像這樣頻繁出現(xiàn)的相同的表達式,我們可以使用 @Pointcut注解聲明切點表達式,然后使用表達式,修改代碼如下:

BuyAspectJ.java

package com.sharpcj.aopdemo.test1;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuyAspectJ {

    @Pointcut("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void point(){}

    @Before("point()")
    public void hehe() {
        System.out.println("before ...");
    }

    @After("point()")
    public void haha() {
        System.out.println("After ...");
    }

    @AfterReturning("point()")
    public void xixi() {
        System.out.println("AfterReturning ...");
    }

    @Around("point()")
    public void xxx(ProceedingJoinPoint pj) {
        try {
            System.out.println("Around aaa ...");
            pj.proceed();
            System.out.println("Around bbb ...");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

程序運行結(jié)果沒有變化。

這里,我們使用

@Pointcut("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
public void point(){}

聲明了一個切點表達式,該方法 point 的內(nèi)容并不重要,方法名也不重要,實際上它只是作為一個標(biāo)識,供通知使用。

4.4、通過注解處理通知中的參數(shù)

上面的例子,我們要進行增強處理的目標(biāo)方法沒有參數(shù),下面我們來說說有參數(shù)的情況,并且在增強處理中使用該參數(shù)。
下面我們給接口增加一個參數(shù),表示購買所花的金錢。通過AOP 增強處理,如果女孩買衣服超過了 68 元,就可以贈送一雙襪子。

更改代碼如下:

IBuy.java

package com.sharpcj.aopdemo.test1;

public interface IBuy {
    String buy(double price);
}

Girl.java

package com.sharpcj.aopdemo.test1;

import org.springframework.stereotype.Component;

@Component
public class Girl implements IBuy {
    @Override
    public String buy(double price) {
        System.out.println(String.format("女孩花了%s元買了一件漂亮的衣服", price));
        return "衣服";
    }
}

Boy.java

package com.sharpcj.aopdemo.test1;

import org.springframework.stereotype.Component;

@Component
public class Boy implements IBuy {
    @Override
    public String buy(double price) {
        System.out.println(String.format("男孩花了%s元買了一個游戲機", price));
        return "游戲機";
    }
}

再看 BuyAspectJ 類,我們將之前的通知都注釋掉。用一個環(huán)繞通知來實現(xiàn)這個功能:

package com.sharpcj.aopdemo.test1;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuyAspectJ {

    /*
    @Pointcut("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void point(){}

    @Before("point()")
    public void hehe() {
        System.out.println("before ...");
    }

    @After("point()")
    public void haha() {
        System.out.println("After ...");
    }

    @AfterReturning("point()")
    public void xixi() {
        System.out.println("AfterReturning ...");
    }

    @Around("point()")
    public void xxx(ProceedingJoinPoint pj) {
        try {
            System.out.println("Around aaa ...");
            pj.proceed();
            System.out.println("Around bbb ...");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
    */


    @Pointcut("execution(String com.sharpcj.aopdemo.test1.IBuy.buy(double)) && args(price) && bean(girl)")
    public void gif(double price) {
    }

    @Around("gif(price)")
    public String hehe(ProceedingJoinPoint pj, double price){
        try {
            pj.proceed();
            if (price > 68) {
                System.out.println("女孩買衣服超過了68元,贈送一雙襪子");
                return "衣服和襪子";
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return "衣服";
    }
}

前文提到,當(dāng)不關(guān)心方法返回值的時候,我們在編寫切點指示器的時候使用了 * , 當(dāng)不關(guān)心方法參數(shù)的時候,我們使用了 ..。現(xiàn)在如果我們需要傳入?yún)?shù),并且有返回值的時候,則需要使用對應(yīng)的類型。在編寫通知的時候,我們也需要聲明對應(yīng)的返回值類型和參數(shù)類型。

測試類:AppTest.java

package com.sharpcj.aopdemo;

import com.sharpcj.aopdemo.test1.Boy;
import com.sharpcj.aopdemo.test1.Girl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AppTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Boy boy = context.getBean("boy",Boy.class);
        Girl girl = (Girl) context.getBean("girl");
        String boyBought = boy.buy(35);
        String girlBought = girl.buy(99.8);

        System.out.println("男孩買到了:" + boyBought);
        System.out.println("女孩買到了:" + girlBought);
    }
}

測試結(jié)果:


可以看到,我們成功通過 AOP 實現(xiàn)了需求,并將結(jié)果打印了出來。

4.5、通過注解配置織入的方式

前面還有一個遺留問題,在配置文件中,我們用注解 @EnableAspectJAutoProxy() 啟用Spring AOP 的時候,我們給參數(shù) proxyTargetClass 賦值為 true,如果我們不寫參數(shù),默認(rèn)為 false。這個時候運行程序,程序拋出異常

這是一個強制類型轉(zhuǎn)換異常。為什么會拋出這個異常呢?或許已經(jīng)能夠想到,這跟Spring AOP 動態(tài)代理的機制有關(guān),這個 proxyTargetClass 參數(shù)決定了代理的機制。當(dāng)這個參數(shù)為 false 時,通過jdk的基于接口的方式進行織入,這時候代理生成的是一個接口對象,將這個接口對象強制轉(zhuǎn)換為實現(xiàn)該接口的一個類,自然就拋出了上述類型轉(zhuǎn)換異常。

反之,proxyTargetClass 為 true,則會使用 cglib 的動態(tài)代理方式。這種方式的缺點是拓展類的方法被final修飾時,無法進行織入。

測試一下,我們將 proxyTargetClass 參數(shù)設(shè)為 true,同時將 Girl.java 的 Buy 方法用 final 修飾:

AppConfig.java

package com.sharpcj.aopdemo;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackageClasses = {com.sharpcj.aopdemo.test1.IBuy.class})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
}

Girl.java

package com.sharpcj.aopdemo.test1;

import org.springframework.stereotype.Component;

@Component
public class Girl implements IBuy {
    @Override
    public final String buy(double price) {
        System.out.println(String.format("女孩花了%s元買了一件漂亮的衣服", price));
        return "衣服";
    }
}

此時運行結(jié)果:

可以看到,我們的切面并沒有織入生效。

五、通過 XML 配置文件聲明切面

前面的示例中,我們已經(jīng)展示了如何通過注解配置去聲明切面,下面我們看看如何在 XML 文件中聲明切面。下面先列出 XML 中聲明 AOP 的常用元素:

我們依然可以使用 <aop:aspectj-autoproxy> 元素,他能夠自動代理AspectJ注解的通知類。

5.1、XML 配置文件中切點指示器

在XML配置文件中,切點指示器表達式與通過注解配置的寫法基本一致,區(qū)別前面有提到,即XML文件中需要使用 “and”、“or”、“not”來表示 “且”、“或”、“非”的關(guān)系。

5.2、XML 文件配置 AOP 實例

下面我們不使用任何注解改造上面的例子:
BuyAspectJ.java

package com.sharpcj.aopdemo.test2;

import org.aspectj.lang.ProceedingJoinPoint;

public class BuyAspectJ {

    public void hehe() {
        System.out.println("before ...");
    }

    public void haha() {
        System.out.println("After ...");
    }

    public void xixi() {
        System.out.println("AfterReturning ...");
    }

    public void xxx(ProceedingJoinPoint pj) {
        try {
            System.out.println("Around aaa ...");
            pj.proceed();
            System.out.println("Around bbb ...");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

在 Resource 目錄下新建一個配置文件 aopdemo.xml :

<?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">

    <bean id="boy" class="com.sharpcj.aopdemo.test2.Boy"></bean>
    <bean id="girl" class="com.sharpcj.aopdemo.test2.Girl"></bean>
    <bean id="buyAspectJ" class="com.sharpcj.aopdemo.test2.BuyAspectJ"></bean>

    <aop:config proxy-target-class="true">
        <aop:aspect id="qiemian" ref="buyAspectJ">
            <aop:before pointcut="execution(* com.sharpcj.aopdemo.test2.IBuy.buy(..))" method="hehe"/>
            <aop:after pointcut="execution(* com.sharpcj.aopdemo.test2.IBuy.buy(..))" method="haha"/>
            <aop:after-returning pointcut="execution(* com.sharpcj.aopdemo.test2.IBuy.buy(..))" method="xixi"/>
            <aop:around pointcut="execution(* com.sharpcj.aopdemo.test2.IBuy.buy(..))" method="xxx"/>
        </aop:aspect>
    </aop:config>
</beans>

這里分別定義了一個切面,里面包含四種類型的通知。

測試文件中,使用

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aopdemo.xml");

來獲取 ApplicationContext,其它代碼不變。

5.3、XML 文件配置聲明切點

對于頻繁重復(fù)使用的切點表達式,我們也可以聲明成切點。

配置文件如下:aopdemo.xml

<?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">

    <bean id="boy" class="com.sharpcj.aopdemo.test2.Boy"></bean>
    <bean id="girl" class="com.sharpcj.aopdemo.test2.Girl"></bean>
    <bean id="buyAspectJ" class="com.sharpcj.aopdemo.test2.BuyAspectJ"></bean>

    <aop:config proxy-target-class="true">
        <aop:pointcut id="apoint" expression="execution(* com.sharpcj.aopdemo.test2.IBuy.buy(..))"/>
        <aop:aspect id="qiemian" ref="buyAspectJ">
            <aop:before pointcut-ref="apoint" method="hehe"/>
            <aop:after pointcut-ref="apoint" method="haha"/>
            <aop:after-returning pointcut-ref="apoint" method="xixi"/>
            <aop:around pointcut-ref="apoint" method="xxx"/>
        </aop:aspect>
    </aop:config>
</beans>

5.4、XML文件配置為通知傳遞參數(shù)

BuyAspectJ.java

package com.sharpcj.aopdemo.test2;

import org.aspectj.lang.ProceedingJoinPoint;

public class BuyAspectJ {
public String hehe(ProceedingJoinPoint pj, double price){
        try {
            pj.proceed();
            if (price > 68) {
                System.out.println("女孩買衣服超過了68元,贈送一雙襪子");
                return "衣服和襪子";
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return "衣服";
    }
}

aopdemo.xml

<?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">

    <bean id="boy" class="com.sharpcj.aopdemo.test2.Boy"></bean>
    <bean id="girl" class="com.sharpcj.aopdemo.test2.Girl"></bean>
    <bean id="buyAspectJ" class="com.sharpcj.aopdemo.test2.BuyAspectJ"></bean>

    <aop:config proxy-target-class="true">
        <aop:pointcut id="apoint" expression="execution(String com.sharpcj.aopdemo.test2.IBuy.buy(double)) and args(price) and bean(girl)"/>
        <aop:aspect id="qiemian" ref="buyAspectJ">
            <aop:around pointcut-ref="apoint" method="hehe"/>
        </aop:aspect>
    </aop:config>
</beans>

5.5、Xml 文件配置織入的方式

同注解配置類似,

CGlib 代理方式:

<aop:config proxy-target-class="true"> </aop:config>

JDK 代理方式:

<aop:config proxy-target-class="false"> </aop:config>

六、總結(jié)

本文簡單記錄了 AOP 的編程思想,然后介紹了 Spring 中 AOP 的相關(guān)概念,以及通過注解方式和XML配置文件兩種方式使用 Spring AOP進行編程。 相比于 AspectJ 的面向切面編程,Spring AOP 也有一些局限性,但是已經(jīng)可以解決開發(fā)中的絕大多數(shù)問題了,如果確實遇到了 Spring AOP 解決不了的場景,我們依然可以在 Spring 中使用 AspectJ 來解決。

以上就是解析Spring中面向切面編程的詳細(xì)內(nèi)容,更多關(guān)于Spring面向切面編程的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java多線程實現(xiàn)文件下載

    java多線程實現(xiàn)文件下載

    這篇文章主要為大家詳細(xì)介紹了java多線程實現(xiàn)文件下載,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • java關(guān)鍵字static的使用詳解

    java關(guān)鍵字static的使用詳解

    這篇文章主要介紹了java關(guān)鍵字static的使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Java Lambda表達式與引用類淺析

    Java Lambda表達式與引用類淺析

    Lambda表達式是Java SE8中一個重要的新特性,允許通過表達式來代替功能接口。本文將通過一些簡單的示例和大家講講Lamda表達式的使用,感興趣的可以了解一下
    2023-01-01
  • 解決IDEA報錯Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded

    解決IDEA報錯Caused by: org.springframework.boot.web.se

    遇到IDEA啟動報錯,可嘗試以下方法:打開項目設(shè)置(Ctrl+Shift+Alt+S),將JDK版本修改為1.8;或者檢查TomCat依賴,若有問題可嘗試刪除,此外,確保每次拉取項目后,maven地址設(shè)置為本地,并且JDK版本設(shè)置為1.8,以上為個人解決經(jīng)驗,希望對大家有所幫助
    2024-09-09
  • Java CompletableFuture使用方式

    Java CompletableFuture使用方式

    這篇文章主要介紹了Java CompletableFuture使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 關(guān)于Prometheus + Spring Boot 應(yīng)用監(jiān)控的問題

    關(guān)于Prometheus + Spring Boot 應(yīng)用監(jiān)控的問題

    這篇文章主要介紹了關(guān)于Prometheus + Spring Boot 應(yīng)用監(jiān)控的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Java ThreadLocal的設(shè)計理念與作用

    Java ThreadLocal的設(shè)計理念與作用

    這篇文章主要介紹了Java ThreadLocal的設(shè)計理念與作用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Java 線程的生命周期完整實例分析

    Java 線程的生命周期完整實例分析

    這篇文章主要介紹了Java 線程的生命周期,結(jié)合完整實例形式分析了java線程周期相關(guān)的加鎖、釋放鎖、阻塞、同步等原理與操作技巧,需要的朋友可以參考下
    2019-10-10
  • MyBatis-Plus實現(xiàn)字段自動填充功能的示例

    MyBatis-Plus實現(xiàn)字段自動填充功能的示例

    本文主要介紹了MyBatis-Plus實現(xiàn)字段自動填充功能的示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Java中內(nèi)存溢出和內(nèi)存泄漏如何解決

    Java中內(nèi)存溢出和內(nèi)存泄漏如何解決

    ?內(nèi)存溢出?和?內(nèi)存泄漏?是兩種常見的內(nèi)存管理問題,它們都會對程序的性能產(chǎn)生負(fù)面影響,本文主要介紹了Java中的內(nèi)存溢出和內(nèi)存泄漏問題解決,感興趣的可以了解一下
    2024-12-12

最新評論

河池市| 盐边县| 禹州市| 屯留县| 孟村| 白城市| 邻水| 林口县| 新巴尔虎右旗| 渑池县| 余江县| 麦盖提县| 涞水县| 永安市| 涡阳县| 星子县| 盱眙县| 滨州市| 佛坪县| 葫芦岛市| 册亨县| 澄江县| 潮州市| 蓝山县| 即墨市| 集安市| 太保市| 天祝| 石楼县| 新昌县| 从化市| 阿荣旗| 泾阳县| 丹东市| 永善县| 鄱阳县| 长兴县| 宾川县| 集贤县| 偃师市| 青河县|