国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring AOP官方文檔學(xué)習(xí)筆記(二)之基于注解的Spring AOP

這篇具有很好參考價(jià)值的文章主要介紹了Spring AOP官方文檔學(xué)習(xí)筆記(二)之基于注解的Spring AOP。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1.@Aspect注解

(1) @Aspect注解用于聲明一個(gè)切面類,我們可在該類中來自定義切面,早在Spring之前,AspectJ框架中就已經(jīng)存在了這么一個(gè)注解,而Spring為了提供統(tǒng)一的注解風(fēng)格,因此采用了和AspectJ框架相同的注解方式,這便是@Aspect注解的由來,換句話說,在Spring想做AOP框架之前,AspectJ AOP框架就已經(jīng)很火了,而直接把AspectJ搬過來又不現(xiàn)實(shí),因此,Spring想了一個(gè)折中的方案,即只使用AspectJ框架的聲明,寫法和定義方式(比如@Aspect注解),而底層由Spring自己實(shí)現(xiàn),這樣,就避免了我們程序員從AspectJ AOP切換到Spring AOP后,還要再去學(xué)一套新的寫法了,也正因?yàn)槿绱?,如果想要使用Spring AOP,就必須依賴aspectjweaver.jar包(不然誰來提供寫法和定義方式),我們可以通過maven進(jìn)行導(dǎo)入,如下

<!-- 添加對AspectJ框架的依賴 -->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.9.5</version>
</dependency>

<!-- 除了上面的方式外,也可以直接使用spring-aspects依賴,它里面包含了對AspectJ的依賴 -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>${spring.framework.version}</version>
</dependency>

(2) 同時(shí)還需使用@EnableAspectJAutoProxy注解來開啟Spring對于AspectJ注解的支持,如下

@Configuration
@EnableAspectJAutoProxy
public class Config {

}

如果是基于xml的配置,可通過如下標(biāo)簽進(jìn)行開啟

<aop:aspectj-autoproxy/>

2.自定義一個(gè)切面類

(1) 在基于注解的配置下,除了使用@Aspect注解外,還需要聲明該切面是一個(gè)bean,否則,spring在掃描過程中是會忽略掉這個(gè)類的,如下

@Aspect
@Component
public class Logger {

}

(2) 對上面的例子,基于xml配置的寫法如下

@Aspect
public class Logger {

}

<!-- xml配置文件中 -->
<beans ...>
    <!-- 無論何種配置方式,不要忘了將切面類注冊為spring的一個(gè)bean -->
    <bean id="logger" class="cn.example.spring.boke.Logger"></bean>
</beans>

(3) 由@Aspect注解標(biāo)注的類,稱之為切面類,與普通的類一樣,都有成員方法與成員變量,不同的是,切面類還可以包含連接點(diǎn),通知,引介等與AOP有關(guān)的東西

(4) 切面不能再被增強(qiáng),如果想拿一個(gè)切面來增強(qiáng)另一個(gè)切面,是不可能的,Spring會將切面類從自動(dòng)代理(auto-proxying)中排除

3.自定義一個(gè)切入點(diǎn)

(1) Spring AOP中的切入點(diǎn)目前只可能是bean中的方法,而對于一個(gè)普通類中的方法,是不可能成為切入點(diǎn)的,在Spring中,聲明一個(gè)切入點(diǎn)主要包括兩個(gè)部分:一個(gè)切入點(diǎn)簽名以及一個(gè)切入點(diǎn)表達(dá)式,如下

//如下定義了一個(gè)叫做anyExampleAMethod的切入點(diǎn),這個(gè)切入點(diǎn)會匹配cn.example.spring.boke包下的ExampleA類中的任何方法
//其中,(1)就代表的是切入點(diǎn)表達(dá)式,(2)就代表的是切入點(diǎn)簽名,注意,這個(gè)簽名的返回值必須是void
@Pointcut("execution(* cn.example.spring.boke.ExampleA.*(..))")      //(1)
public void anyExampleAMethod() {}                                   //(2)

(2) Spring AOP的切入點(diǎn)表達(dá)式中,支持如下等切入點(diǎn)標(biāo)識符

  • execution:最為常用,用于匹配某個(gè)包,某個(gè)類中的方法

  • within:進(jìn)行類型匹配,用于匹配某個(gè)包下所有類的所有方法或某個(gè)指定類中的所有方法,如下

//指定了within的類型,這個(gè)切入點(diǎn)會匹配cn.example.spring.boke包下ExampleA類中的任何方法
@Pointcut("within(cn.example.spring.boke.ExampleA)")
public void withinDesignator(){}
  • this:進(jìn)行類型匹配,用于匹配生成的代理對象的類型是否為指定類型,如下
//此前我們提到過,Spring AOP中的底層實(shí)現(xiàn)分為jdk動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理,jdk動(dòng)態(tài)代理基于接口,要求目標(biāo)對象必須實(shí)現(xiàn)某個(gè)接口,而cglib動(dòng)態(tài)代理基于繼承,因此不同的實(shí)現(xiàn)方式下,導(dǎo)致Spring生成的代理對象的類型可能不同,這就是this標(biāo)識符的基礎(chǔ)
//首先定義一個(gè)接口
public interface Parent {
    void register();

    void sendEmail();
}

//讓我們的ExampleA類,實(shí)現(xiàn)這個(gè)接口
@Component
public class ExampleA implements Parent{

    public void register() {

    }

    public void sendEmail() {

    }
}

//設(shè)置@EnableAspectJAutoProxy注解中的proxyTargetClass屬性值為false,表示使用jdk動(dòng)態(tài)代理,為true,表示使用cglib動(dòng)態(tài)代理,默認(rèn)值為false,不過我們這里顯式的聲明出來
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ComponentScan(basePackages = "cn.example.spring.boke")
public class Config {

}

//切面類,在其中聲明一個(gè)this標(biāo)識符,并指定類型為ExampleA
@Aspect
@Component
public class Logger {
    /**
     * this標(biāo)識符,進(jìn)行類型匹配,用于匹配代理對象的類型是否為指定類型
     */
    @Pointcut(value = "this(cn.example.spring.boke.ExampleA)")
    public void thisDesignator(){}

    @Around(value = "thisDesignator()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println(new Date() + " 開始執(zhí)行...");
        joinPoint.proceed();
        System.out.println(new Date() + " 結(jié)束執(zhí)行...");
    }
}

//執(zhí)行如下打印方法,可見通知未被執(zhí)行,原因就是因?yàn)槲覀兪褂昧薺dk動(dòng)態(tài)代理,Spring為我們生成的代理對象繼承自jdk中的Proxy類并實(shí)現(xiàn)了Parent接口,它不屬于ExampleA類型,自然而然切入點(diǎn)匹配失敗,我們的通知未被執(zhí)行
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
ctx.getBean(Parent.class).register();
ctx.getBean(Parent.class).sendEmail();

//打印一下系統(tǒng)中代理對象的類型是否為ExampleA,結(jié)果為false
System.out.println(ctx.getBean(Parent.class) instanceof ExampleA);


//為了能進(jìn)行匹配,我們可以將@EnableAspectJAutoProxy中的proxyTargetClass屬性設(shè)置為true,使用cglib動(dòng)態(tài)代理,這時(shí)再執(zhí)行上面的打印方法,通知就會被執(zhí)行了,原因就是因?yàn)槭褂昧薱glib動(dòng)態(tài)代理后,Spring為我們生成的代理對象是繼承自ExampleA,當(dāng)然屬于ExampleA類型,因此通知會被執(zhí)行
@EnableAspectJAutoProxy(proxyTargetClass = true)
  • target:進(jìn)行類型匹配,用于匹配目標(biāo)對象的類型是否為指定類型,跟上面的this類似

  • args:進(jìn)行方法參數(shù)匹配,用于匹配方法的參數(shù)類型是否為指定類型,如下

//ExampleA中的register方法的參數(shù)為String
@Component
public class ExampleA{

    public void register(String name) {

    }

    public void sendEmail() {

    }
}

@Aspect
@Component
public class Logger {
    /**
     * 指定了args參數(shù)的類型為String,因此只會與ExampleA中的register方法匹配
     */
    @Pointcut(value = "args(java.lang.String)")
    public void argsDesignator() {}

    @Around(value = "argsDesignator()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println(new Date() + " 開始執(zhí)行...");
        joinPoint.proceed();
        System.out.println(new Date() + " 結(jié)束執(zhí)行...");
    }
}
  • @target:用于匹配目標(biāo)對象的類上有沒有標(biāo)注指定注解

  • @args:用于匹配方法的參數(shù)的所屬類上有沒有標(biāo)注指定注解

  • @within:用于匹配某個(gè)類上有沒有標(biāo)注指定注解

  • @annotation:最常用,用于匹配某個(gè)方法上有沒有標(biāo)注指定注解

(3) Spring的AOP是基于代理實(shí)現(xiàn)的,因此,在目標(biāo)對象中進(jìn)行內(nèi)部調(diào)用是不會被攔截的(即this指針會導(dǎo)致AOP失效問題),此外,對于jdk動(dòng)態(tài)代理,只能攔截public方法,而對于cglib動(dòng)態(tài)代理,會攔截public和protected方法(package-visible 方法在配置后也能被攔截)

(4) Spring AOP還提供了一個(gè)PCD bean,用于按照bean的名稱進(jìn)行切入,它是Spring AOP獨(dú)有的,如下

//匹配所有beanName以A結(jié)尾的bean
@Pointcut("bean(*A)")
public void pcd() {}

4.組合切入點(diǎn)表達(dá)式

(1) 可以通過 &&,|| 和 !來組合切入點(diǎn)表達(dá)式,如下

//切入所有public方法
@Pointcut("execution(public * *(..))")
public void allPublicMethod() {}

//切入boke包下所有類中的所有方法
@Pointcut("within(cn.example.spring.boke.*)")
public void methodInBokePackage() {}

//使用 && 操作符,將上面兩個(gè)切入點(diǎn)表達(dá)式組合起來,即切入boke包下所有類中的所有public方法
@Pointcut("allPublicMethod() && methodInBokePackage()")
public void allPublicMethodInBokePackage() {}

5.常見切入點(diǎn)表達(dá)式例子

(1)在實(shí)際工作中,我們的切入點(diǎn)表達(dá)式的通常形式為:execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?),其中ret-type-pattern表示一個(gè)方法的返回類型, 用 * 號可以代表任何類型; name-pattern表示方法名稱,用 * 可以進(jìn)行全部或部分名稱匹配; param-pattern表示方法參數(shù),其中用()代表無參方法,用(..)代表任何數(shù)量的參數(shù)(0個(gè)或多個(gè)),用()代表1個(gè)參數(shù),(, String)代表有兩個(gè)參數(shù),第一個(gè)參數(shù)可以是任何類型,而第二個(gè)參數(shù)只能是String類型; 除此之外,其他帶有 ? 的都是選填項(xiàng),可不填寫

(2)常見例子

//匹配任意public方法
 execution(public * *(..))

//匹配任意名稱以set開頭的方法
execution(* set*(..))

//匹配com.xyz.service包下,AccountService類下的任意方法
execution(* com.xyz.service.AccountService.*(..))

//匹配com.xyz.service包下,任意類下的任意方法
execution(* com.xyz.service.*.*(..))

//匹配com.xyz.service包及其子包下,任意類下的任意方法
execution(* com.xyz.service..*.*(..))

//匹配com.xyz.service包下,任意類下的任意方法
within(com.xyz.service.*)

//匹配com.xyz.service包及其子包下,任意類下的任意方法
within(com.xyz.service..*)

//匹配代理對象的類型為AccountService的類下的任意方法
this(com.xyz.service.AccountService)

//匹配目標(biāo)對象的類型為AccountService的類下的任意方法
target(com.xyz.service.AccountService)

//匹配方法參數(shù)只有一個(gè)且參數(shù)類型為Serializable的方法,注意它與execution(* *(java.io.Serializable))的一點(diǎn)區(qū)別:execution這個(gè)例子只能匹配參數(shù)類型為Serializable的方法,如果說某個(gè)方法的參數(shù)類型是Serializable的子類,是不會匹配的,而下面args這個(gè)例子可以匹配參數(shù)類型為Serializable或其子類的方法
args(java.io.Serializable)

//匹配標(biāo)注了@Transactional注解的目標(biāo)對象中的任意方法
@target(org.springframework.transaction.annotation.Transactional)

//匹配標(biāo)注了@Transactional注解的類中的任意方法
@within(org.springframework.transaction.annotation.Transactional)

//匹配標(biāo)注了@Transactional注解的任意方法
@annotation(org.springframework.transaction.annotation.Transactional)

//匹配方法的參數(shù)有且只有一個(gè)且該參數(shù)的所屬類上標(biāo)注了@Classified注解的任意方法
@args(com.xyz.security.Classified)

//匹配beanName為tradeService的bean中的任意方法
bean(tradeService)

//匹配所有以Service作為beanName結(jié)尾的bean中的任意方法
bean(*Service)

6.編寫良好的pointcuts

(1)Spring將切入點(diǎn)標(biāo)識符分為3大類,分別為:

  • Kinded:類型標(biāo)識符,如execution, get, set, call等,它們都是根據(jù)類型進(jìn)行選擇,比如execution選擇的都是可執(zhí)行方法這一類型,其中除了execution,其他的都是AspectJ框架提供的
  • Scoping:范圍標(biāo)識符,如within;
  • Contextual:上下文標(biāo)識符,如this, target和@annotation,它們都是根據(jù)方法所處的環(huán)境(比如在哪個(gè)類中)進(jìn)行選擇
    Spring建議一個(gè)良好的切入點(diǎn)表達(dá)式應(yīng)該至少包括前兩種類型(kinded和scoping,在這兩種標(biāo)識符中scoping又特別重要,因?yàn)樗钠ヅ渌俣确浅??,可以快速的排除掉那些不?yīng)該被處理的方法),此外在有根據(jù)上下文環(huán)境的需求時(shí),可以包括contextual標(biāo)識符

7.聲明一個(gè)通知

(1)在前面已經(jīng)提及過通知,它是增強(qiáng)的邏輯,與切入點(diǎn)相關(guān)聯(lián),會在切入點(diǎn)執(zhí)行前或執(zhí)行后執(zhí)行,在Spring中總共分為5大類,如下

  • Before Advice:使用@Before注解可定義前置通知,它會在切入點(diǎn)執(zhí)行之前執(zhí)行
@Aspect
@Component
public class Logger {

    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void before() {
        //...
    }
}
  • After Returning Advice:使用@AfterReturning注解可定義返回通知,它會在切入點(diǎn)"正常"執(zhí)行之后執(zhí)行
//一個(gè)普通的bean ExampleA
@Component
public class ExampleA{
    public String doSomething() {
        return "finish";
    }
}

//有時(shí)候,我們可能需要訪問切入點(diǎn)執(zhí)行后的返回值,那么我們可以使用@AfterReturning注解中的returning屬性來指定返回值的名稱,然后再給這個(gè)切面方法添加一個(gè)形參,這個(gè)形參類型即為切入點(diǎn)執(zhí)行后的返回值類型(或其父類型,但不能完全不一致,否則切面會切入失敗),形參名要與剛剛設(shè)置過的returning屬性值一致,如下例
@Aspect
@Component
public class Logger {

    @AfterReturning(value = "execution(* cn.example.spring.boke.ExampleA.*(..))", returning = "returnVal")
    public void afterReturning(Object returnVal) {
        System.out.println(new Date() + " 開始執(zhí)行...");
        System.out.println(returnVal);
        System.out.println(new Date() + " 結(jié)束執(zhí)行...");
    }
}
  • After Throwing Advice:使用@AfterThrowing注解可定義異常通知,它會在切入點(diǎn)觸發(fā)異常之后執(zhí)行
//同樣,我們有時(shí)候也期望訪問切入點(diǎn)執(zhí)行過程中拋出的異常,與返回通知一致,例子如下
@Aspect
@Component
public class Logger {

    @AfterThrowing(value = "execution(* cn.example.spring.boke.ExampleA.*(..))", throwing = "throwable")
    public void afterReturning(Throwable throwable) {
        System.out.println(new Date() + " 開始執(zhí)行...");
        System.out.println(throwable);
        System.out.println(new Date() + " 結(jié)束執(zhí)行...");
    }
}
  • After (Finally) Advice:使用@After注解可定義后置通知,它會在切入點(diǎn)無論以何種方式執(zhí)行(正?;虍惓#┖髨?zhí)行,常用于釋放資源等目的,類似于try-catch語句中的finally塊,它與@AfterReturning的區(qū)別是,@AfterReturning只適用于切入點(diǎn)正常返回
@Aspect
@Component
public class Logger {

    @After(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void afterReturning() {
        //...
    }
}
  • Around advice:使用@After注解可定義環(huán)繞通知,它既可以在切入點(diǎn)之前執(zhí)行通知,又可以在切入點(diǎn)之后執(zhí)行,甚至可以不用執(zhí)行切入點(diǎn),是最為靈活強(qiáng)大的通知
@Aspect
@Component
public class Logger {
    //環(huán)繞通知方法可不聲明形參,但如果要聲明形參,第一個(gè)形參的類型必須是ProceedingJoinPoint類型,對ProceedingJoinPoint調(diào)用proceed方法后會導(dǎo)致切入點(diǎn)真正的執(zhí)行,此外,proceed方法還有一個(gè)重載方法,我們可以對它傳遞一個(gè)Object[],那么當(dāng)切入點(diǎn)執(zhí)行時(shí)會以這個(gè)數(shù)組中的值作為方法參數(shù)值來執(zhí)行
    //我們可以調(diào)用一次,多次或根本不調(diào)用proceed方法
    @Around(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void afterReturning(ProceedingJoinPoint joinPoint) {
        Object returnVal = null;
        try {
            //...
            returnVal = joinPoint.proceed();
            //...
        } catch (Throwable e) {
            //...
            e.printStackTrace();
        }
        return returnVal;
    }
}

8.切入點(diǎn)信息獲取

(1)有時(shí)候,我們期望獲取到切入點(diǎn)相關(guān)信息,比如它的簽名,形參等信息,Spring為我們提供了JoinPoint類型,用于獲取相關(guān)信息,在前面的環(huán)繞通知的例子中,我們就已經(jīng)使用了JoinPoint的子類型ProceedingJoinPoint,它添加了proceed方法,來顯式的調(diào)用執(zhí)行切入點(diǎn)

@Aspect
@Component
public class Logger {
    //除了下面的例子外,使用JoinPoint,還可以獲取到切入點(diǎn)的其他一些信息,可參考api文檔
    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void before(JoinPoint joinPoint) {
        System.out.println("被攔截的類:" + joinPoint.getTarget().getClass().getName());
        System.out.println("被攔截的方法:" + ((MethodSignature) joinPoint.getSignature()).getMethod().getName());
        System.out.println("被攔截的方法參數(shù):" + Arrays.toString(joinPoint.getArgs()));
    }
}

9.通知執(zhí)行順序

(1)不同切面類中的通知,在默認(rèn)情況下,按照所在切面類名的字典序排序,若其排序越高則優(yōu)先級也就越高,如下

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "cn.example.spring.boke")
public class Config { }

@Component
public class ExampleA{

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

//聲明兩個(gè)切面類TimerLogger和OperationLogger
@Aspect
@Component
public class TimerLogger {
    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void a() {
        System.out.println("timer...");
    }
}


@Aspect
@Component
public class OperationLogger {
    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void a() {
        System.out.println("operation...");
    }
}

//啟動(dòng)容器,觀察打印結(jié)果
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
ctx.getBean(ExampleA.class).doSomething();

//打印結(jié)果如下,OperationLogger中的前置通知先執(zhí)行,TimerLogger中的前置通知后執(zhí)行,就是因?yàn)镺的字典序列大于T,因此OperationLogger中的通知的優(yōu)先級高于TimerLogger中的,而對于前置通知而言,優(yōu)先級越高的越先執(zhí)行,對于后置通知,優(yōu)先級越高的越后執(zhí)行
operation...
timer...
doSomething...


//我們可以將TimerLogger改為ATimerLogger,這樣的話它里面的前置通知就會先執(zhí)行了
@Aspect
@Component
public class ATimerLogger {
    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void a() {
        System.out.println("timer...");
    }
}

(2)我們可以對切面類實(shí)現(xiàn)Ordered接口或添加@Order注解來顯示的指定優(yōu)先級,其中指定的值越小,優(yōu)先級越高

//此時(shí)TimerLogger的優(yōu)先級高于OperationLogger
@Aspect
@Component
@Order(1)
public class TimerLogger {
    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void a() {
        System.out.println("timer...");
    }
}

@Aspect
@Component
@Order(2)
public class OperationLogger {

    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void a() {
        System.out.println("operation...");
    }
}

(3)對于同個(gè)切面類中的相同類型的通知,其優(yōu)先級只與通知方法名字典序的排序有關(guān),排序越高,優(yōu)先級越高,如下

//Logger切面類中定義了兩個(gè)前置通知為aPrint和bPrint
@Aspect
@Component
public class Logger {

    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void aPrint() {
        System.out.println("a");
    }

    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    public void bPrint() {
        System.out.println("b");
    }
}

//啟動(dòng)容器,可見aPrint先于bPrint,這就是因?yàn)閍的字典序高于b
a
b
doSomething...

//將aPrint改為caPrint,這時(shí)bPrint會先執(zhí)行,因?yàn)榇藭r(shí)它的字典序高
@Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
publicvoid caPrint() {
    System.out.println("a");
}

//此外使用@Order注解,無法改變優(yōu)先級,因?yàn)榇藭r(shí)顯式指定優(yōu)先級的策略已經(jīng)失效了,如下面這個(gè)例子還是按照之前默認(rèn)的優(yōu)先級進(jìn)行執(zhí)行
@Aspect
@Component
public class Logger {

    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    @Order(Ordered.LOWEST_PRECEDENCE)
    public void aPrint() {
        System.out.println("a");
    }

    @Before(value = "execution(* cn.example.spring.boke.ExampleA.*(..))")
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public void bPrint() {
        System.out.println("b");
    }
}

10.Introductions(引介)

(1)引介能夠使指定的對象實(shí)現(xiàn)某些接口,并提供對這些接口的實(shí)現(xiàn),以達(dá)到向?qū)ο笾袆?dòng)態(tài)添加它所沒有方法的目的,例子如下文章來源地址http://www.zghlxwxcb.cn/news/detail-416254.html

//我們希望向ExampleA類中增加某些新的方法
@Component
public class ExampleA{ }

//聲明一個(gè)接口,這個(gè)接口里的方法即為我們希望增加的新的方法
public interface Extention {
    void doSomething();
}

//新方法的具體實(shí)現(xiàn)
public class ExtentionImpl implements Extention{

    @Override
    public void doSomething() {
        System.out.println("doSomething...");
    }
}

//定義一個(gè)切面
@Component
@Aspect
public class MyAspect {
    //使用@DeclarePrents注解,聲明被攔截的類有一個(gè)新的父類型,其中value指定攔截哪些類,在下面這個(gè)例子中指定攔截cn.example.spring.boke包下的所有類,同時(shí)指定它們的父類型均為Extention,具體的實(shí)現(xiàn)為ExtentionImpl
    @DeclareParents(value = "cn.example.spring.boke.*", defaultImpl = ExtentionImpl.class)
    public Extention extention;
}

//開啟AOP
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "cn.example.spring.boke")
public class Config { }

//啟動(dòng)容器,從容器中獲取到exampleA并將其強(qiáng)制轉(zhuǎn)換為Extention,這樣我們就能使用向ExampleA中新添加的方法了
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
Extention exampleA = (Extention)ctx.getBean("exampleA");
exampleA.doSomething();

到了這里,關(guān)于Spring AOP官方文檔學(xué)習(xí)筆記(二)之基于注解的Spring AOP的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spring MVC官方文檔學(xué)習(xí)筆記(一)之Web入門

    Spring MVC官方文檔學(xué)習(xí)筆記(一)之Web入門

    注: 該章節(jié)主要為原創(chuàng)內(nèi)容,為后續(xù)的Spring MVC內(nèi)容做一個(gè)先行鋪墊 1.Servlet的構(gòu)建使用 (1) 選擇Maven - webapp來構(gòu)建一個(gè)web應(yīng)用 (2) 構(gòu)建好后,打開pom.xml文件,一要注意打包方式為war包,二導(dǎo)入servlet依賴,如下 (3) 替換webapp/WEB-INF/web.xml文件為如下內(nèi)容,采用Servlet 3.1版本 (4) 在

    2024年02月03日
    瀏覽(34)
  • ros2官方文檔(基于humble版本)學(xué)習(xí)筆記

    ros2官方文檔(基于humble版本)學(xué)習(xí)筆記

    由于市面上專門講ROS 2開發(fā)的書籍不多,近期看完了《ROS機(jī)器人開發(fā)實(shí)踐》其中大部分內(nèi)容還是基于ROS 1寫的,涉及topic,service,action等一些重要的概念,常用組件,建模與仿真,應(yīng)用(機(jī)器視覺,機(jī)器語音,SLAM,機(jī)械臂),最后一章寫了ROS 2的安裝,話題通信和服務(wù)通信的示

    2024年02月11日
    瀏覽(28)
  • ROS 2官方文檔(基于humble版本)學(xué)習(xí)筆記(二)

    ROS 2官方文檔(基于humble版本)學(xué)習(xí)筆記(二)

    今天繼續(xù)總結(jié)CLI 工具章的學(xué)習(xí) 理解節(jié)點(diǎn)(node) ROS 2圖是一個(gè)ROS 2元件同時(shí)處理數(shù)據(jù)的網(wǎng)絡(luò),如果將它們?nèi)坑成洳⒖梢暬鼈?,則包括所有可執(zhí)行文件以及它們之間的連接。 ROS中的每個(gè)節(jié)點(diǎn)(node)都應(yīng)該只為了單個(gè)的、模塊化的目的而設(shè)計(jì)的,例如控制車輪電動(dòng)機(jī)或從激光

    2024年02月10日
    瀏覽(16)
  • 注解實(shí)現(xiàn)(基于Spring AOP)

    切入點(diǎn)表達(dá)式 Spring AOP 支持的切入點(diǎn)主要有以下幾種: execution:用于匹配方法執(zhí)行的連接點(diǎn)。這是最常用的切入點(diǎn)指示器。你可以指定具體的方法,或者類來匹配。 例如: execution(* com.example.service.*.*(..)) ,這個(gè)表達(dá)式表示匹配 com.example.service 包下的所有類的所有方法。 wit

    2024年02月16日
    瀏覽(18)
  • Spring——基于注解的AOP配置

    Spring——基于注解的AOP配置

    1.1.pom.xml 1.2.dao 1.3.service 1.4.applicationContext.xml 1.5.測試 2.1.applicationContext.xml 2.2.AOP配置 常用注解 @Aspect:把當(dāng)前類聲明為切面類 @Before:前置通知,可以指定切入點(diǎn)表達(dá)式 @AfterReturning:后置【try】通知,可以指定切入點(diǎn)表達(dá)式 @AfterThrowing:異常【catch】通知,可以指定切入點(diǎn)表達(dá)

    2024年01月22日
    瀏覽(19)
  • 11、Spring之基于注解的AOP

    11、Spring之基于注解的AOP

    創(chuàng)建名為spring_aop_annotation的新module,過程參考9.1節(jié) 注意:AOP需要在IOC的基礎(chǔ)上實(shí)現(xiàn),因此需要導(dǎo)入IOC的依賴 11.2.1.1、配置前置方法 11.2.1.2、測試使用效果 由控制臺日志可知,切面類的前置通知(方法),通過切入點(diǎn)表達(dá)式,作用到了目標(biāo)方法的連接點(diǎn)上 11.2.2.1、改進(jìn)前置方

    2024年02月13日
    瀏覽(27)
  • Spring02-Spring注解的使用、基于注解的IOC、純注解配置、整合Junit、AOP入門、基于配置文件的AOP、切入點(diǎn)表達(dá)式、基于配置的文件環(huán)繞通知

    學(xué)習(xí)基于注解的 IOC 配置,即注解配置 和 XML 配置要實(shí)現(xiàn)的功能都是一樣的,都是要降低程序間的耦合。只是配置的形式不一樣。 關(guān)于實(shí)際的開發(fā)中到底使用xml還是注解,每家公司有著不同的使用習(xí)慣 , 所以這兩種配置方式我們都需要掌握。 把 Spring 的 xml 配置內(nèi)容改為使用

    2024年02月03日
    瀏覽(19)
  • 【Spring進(jìn)階系列丨第十篇】基于注解的面向切面編程(AOP)詳解

    【Spring進(jìn)階系列丨第十篇】基于注解的面向切面編程(AOP)詳解

    ? 注意,該類的兩個(gè)細(xì)節(jié): a、@Component注解向容器中注冊一個(gè)Bean。 b、@Aspect注解表示這個(gè)是一個(gè)切面類。 c、@Before注解表示的是這個(gè)是前置增強(qiáng)/前置通知。 ? 注意:對于業(yè)務(wù)Bean,我們也需要通過@Service注解來向容器中注冊。 ? 問題:我們看到對于切面類中定義的通知,有

    2024年04月23日
    瀏覽(28)
  • Spring Boot學(xué)習(xí)隨筆- 實(shí)現(xiàn)AOP(JoinPoint、ProceedingJoinPoint、自定義注解類實(shí)現(xiàn)切面)

    Spring Boot學(xué)習(xí)隨筆- 實(shí)現(xiàn)AOP(JoinPoint、ProceedingJoinPoint、自定義注解類實(shí)現(xiàn)切面)

    學(xué)習(xí)視頻:【編程不良人】2021年SpringBoot最新最全教程 問題 現(xiàn)有業(yè)務(wù)層開發(fā)存在問題 額外功能代碼存在大量冗余 每個(gè)方法都需要書寫一遍額外功能代碼不利于項(xiàng)目維護(hù) Spring中的AOP AOP:Aspect 切面 + Oriented 面向 Programmaing 面向切面編程 Aspect(切面) = Advice(通知) + Pointcut(

    2024年02月04日
    瀏覽(43)
  • Spring Boot入門(23):基于AOP實(shí)現(xiàn)自定義注解攔截接口日志并保存入庫 | 超級詳細(xì),建議收藏

    Spring Boot入門(23):基于AOP實(shí)現(xiàn)自定義注解攔截接口日志并保存入庫 | 超級詳細(xì),建議收藏

    ? ? ? ? 在上兩期中,我們著重介紹了如何集成使用 Logback?與?log4j2?日志框架的使用,今天我們講解的主題依舊跟日志有關(guān),不過不是使用何種開源框架,而是自己動(dòng)手造。 ? ? ? ? Spring的核心之一AOP;AOP翻譯過來叫面向切面編程, 核心就是這個(gè)切面. 切面表示從業(yè)務(wù)邏輯中

    2024年02月11日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包