[Spring中的通知(Advice)和顧問(Advisor)]

Spring中的通知(Advice)和顧問(Advisor)

在Spring中,目前我學(xué)習(xí)了幾種增強(qiáng)的方式,和大家分享一下

之前的話:

1.AOP (Aspect Oriented Programming 面向切面編程)

在軟件業(yè),AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預(yù)編譯方式和運(yùn)行期動態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。AOP是OOP的延續(xù),是軟件開發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容,是函數(shù)式編程的一種衍生范型。利用AOP可以對業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開發(fā)的效率。

面向?qū)ο缶幊淌菑摹眷o態(tài)角度】考慮程序的結(jié)構(gòu),而面向切面編程是從【動態(tài)角度】考慮程序運(yùn)行過程。
AOP底層,就是采用【動態(tài)代理】模式實(shí)現(xiàn)的。采用了兩種代理:JDK動態(tài)代理和CGLIB動態(tài)代理。

基本術(shù)語(一些名詞):
(1)切面(Aspect)
切面泛指[交叉業(yè)務(wù)邏輯]。事務(wù)處理和日志處理可以理解為切面。常用的切面有通知(Advice)與顧問(Advisor)。實(shí)際就是對主業(yè)務(wù)邏輯的一種增強(qiáng)。

(2)織入(Weaving)
織入是指將切面代碼插入到目標(biāo)對象的過程。代理的invoke方法完成的工作,可以稱為織入。

(3) 連接點(diǎn)(JoinPoint)
連接點(diǎn)是指可以被切面織入的方法。通常業(yè)務(wù)接口的方法均為連接點(diǎn)

(4)切入點(diǎn)(PointCut)
切入點(diǎn)指切面具體織入的方法
注意:被標(biāo)記為final的方法是不能作為連接點(diǎn)與切入點(diǎn)的。因?yàn)樽罱K的是不能被修改的,不能被增強(qiáng)的。

(5)目標(biāo)對象(Target)
目標(biāo)對象指將要被增強(qiáng)的對象。即包含主業(yè)務(wù)邏輯的類的對象。

(6)通知(Advice)
通知是切面的一種實(shí)現(xiàn),可以完成簡單的織入功能。通知定義了增強(qiáng)代碼切入到目標(biāo)代碼的時(shí)間點(diǎn),是目標(biāo)方法執(zhí)行之前執(zhí)行,還是執(zhí)行之后執(zhí)行等。切入點(diǎn)定義切入的位置,通知定義切入的時(shí)間。

(7)顧問(Advisor)
顧問是切面的另一種實(shí)現(xiàn),能夠?qū)⑼ㄖ愿鼮閺?fù)雜的方式織入到目標(biāo)對象中,是將通知包裝為更復(fù)雜切面的裝配器。

AOP是一種思想,而非實(shí)現(xiàn)
AOP是基于OOP,而又遠(yuǎn)遠(yuǎn)高于OOP,主要是將主要核心業(yè)務(wù)和交叉業(yè)務(wù)分離,交叉業(yè)務(wù)就是切面。例如,記錄日志和開啟事務(wù)。

一:前置增強(qiáng)和后置增強(qiáng)

image

源碼介紹:

1.User.java

image

View Code

2.IDao.java

image

View Code

3.UserDao.java

image

View Code

4.IUserBiz.java

image

View Code

5.UserBiz.java

image

View Code

6.LoggerAfter.java(后置增強(qiáng))

image

View Code

7.LoggerBefore.java(前置增強(qiáng))

image

View Code

8.applicationContext.xml(Spring配置文件)

image

View Code

當(dāng)然,針對AOP的配置也可以使用代理對象 ProxyFactoryBean 代理工廠bean來實(shí)現(xiàn),在測試類中:IUserBiz biz=(IUserBiz)ctx.getBean("serviceProxy");

image

View Code

9.MyTest.java

image

View Code

10.log4j.properties(日志的配置文件)

image

View Code

當(dāng)然,別忘了引入我們需要的jar包啊!

常用的jar:

image

二:異常拋出增強(qiáng)和環(huán)繞增強(qiáng)

image

源碼介紹:

1.User.java

image

View Code

2.UserService.java

image

View Code

3.ErrorLog.java(異常拋出增強(qiáng))

image

View Code

4.AroundLog(環(huán)繞增強(qiáng))

image

View Code

5.applicationContext.xml(Spring配置文件)

image

View Code

6.MyTest.java

image

View Code

三:注解增強(qiáng)方式實(shí)現(xiàn)前置增強(qiáng)和后置增強(qiáng)

image

源碼介紹:

1.UserService.java

image

View Code

2.AnnotationAdvice.java(注解增強(qiáng))

image

View Code

注:

java.lang.Object[] getArgs():獲取連接點(diǎn)方法運(yùn)行時(shí)的入?yún)⒘斜?br> Signature getSignature() :獲取連接點(diǎn)的方法簽名對象
java.lang.Object getTarget() :獲取連接點(diǎn)所在的目標(biāo)對象
java.lang.Object getThis() :獲取代理對象本身

3.applicationContext.xml(Spring配置文件)

image

View Code

4.MyTest.java

image

View Code

四: 顧問(Advisor)實(shí)現(xiàn)前置增強(qiáng)

通知Advice是Spring提供的一種切面(Aspect)。但其功能過于簡單,只能
將切面織入到目標(biāo)類的所有目標(biāo)方法中,無法完成將切面織入到指定目標(biāo)方法中。

顧問Advisor是Spring提供的另一種切面。其可以完成更為復(fù)雜的切面織入功能。PointcutAdvisor是顧問的一種,可以指定具體
的切入點(diǎn)。顧問將通知進(jìn)行了包裝,會根據(jù)不同的通知類型,在不同的時(shí)間點(diǎn),將切面織入到不同的切入點(diǎn)。
PointcutAdvisor接口有兩個(gè)較為常用的實(shí)現(xiàn)類:
:NameMatchMethodPointcutAdvisor 名稱匹配方法切入點(diǎn)顧問
:RegexpMethodPointcutAdvisor 正則表達(dá)式匹配方法切入點(diǎn)顧問
<property name="pattern" value=".
do.
"></property> 表示方法全名(包名,接口名,方法名)
運(yùn)算符 名稱 意義
. 點(diǎn)號 表示任意單個(gè)字符

  • 加號 表示前一個(gè)字符出現(xiàn)一次或者多次
  • 星號 表示前一個(gè)字符出現(xiàn)0次或者多次
    =====默認(rèn)Advisor自動代理生成器
    DefaultAdvisorAutoProxyCreator
    =====BeanName自動代理生成器
    BeanNameAutoProxyCreator

實(shí)例:

image

源碼介紹:

1.ISomeService.java

image

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">package service; //接口
public interface ISomeService { //待實(shí)現(xiàn)的方法
public void doFirst(); public void doSecond();
}</pre>

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

2.SomeServiceImpl.java

image

View Code

3.MyMethodBeforeAdvice.java

image

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">package aop; //前置增強(qiáng)
import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class MyMethodBeforeAdvice implements MethodBeforeAdvice{

@Override public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("目標(biāo)方法執(zhí)行之前執(zhí)行");
}

}</pre>

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

4.applicationContext.xml(Spring配置文件)

image

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><?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" 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">

<!-- 目標(biāo)對象 -->
<bean id="someService" class="service.SomeServiceImpl"></bean>

<!-- 切面:通知 -->
<bean id="beforeAdvice" class="aop.MyMethodBeforeAdvice"></bean>

<!-- *********************************************** -->

<!-- 1.*:NameMatchMethodPointcutAdvisor 名稱匹配方法切入點(diǎn)顧問 -->
<!-- 切面:顧問 顧問(Advisor)要包裝通知(Advice) -->    
<bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> 
    <property name="advice" ref="beforeAdvice"></property> 
    <!--指定需要增強(qiáng)的方法:這里是doFirst()方法,而doSecond()方法則不會增強(qiáng) -->
    <property name="mappedName" value="doFirst"></property>
    <!-- 也可以使用mappedNames指定多個(gè)方法
    <property name="mappedNames" value="doFirst,doSecond"></property> -->
</bean>

<!-- *********************************************** -->

<!-- 2.*:RegexpMethodPointcutAdvisor 正則表達(dá)式匹配方法切入點(diǎn)顧問 -->
<!-- 切面: 顧問 顧問(Advisor)要包裝通知(Advice) -->
<!-- <bean id="beforeAdvisor"
    class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice" ref="beforeAdvice"></property>
    <property name="pattern" value=".*doF.*t"></property>
</bean> -->

<!-- *********************************************** -->

<!-- 代理工廠Bean -->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="someService"></property>
    <property name="interceptorNames" value="beforeAdvisor"></property>
</bean>

</beans></pre>

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

5.MyTest.java

image

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">package test; //對顧問(Advisor)測試
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import service.ISomeService; public class MyTest {
@Test public void testOne(){
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
ISomeService service = (ISomeService)ctx.getBean("serviceProxy");
service.doFirst();
service.doSecond();
}
}</pre>

[

復(fù)制代碼
](javascript:void(0); "復(fù)制代碼")
Spring中的通知(Advice)和顧問(Advisor)

在Spring中,目前我學(xué)習(xí)了幾種增強(qiáng)的方式,和大家分享一下

之前的話:

1.AOP (Aspect Oriented Programming 面向切面編程)

在軟件業(yè),AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預(yù)編譯方式和運(yùn)行期動態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。AOP是OOP的延續(xù),是軟件開發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容,是函數(shù)式編程的一種衍生范型。利用AOP可以對業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開發(fā)的效率。

面向?qū)ο缶幊淌菑摹眷o態(tài)角度】考慮程序的結(jié)構(gòu),而面向切面編程是從【動態(tài)角度】考慮程序運(yùn)行過程。
AOP底層,就是采用【動態(tài)代理】模式實(shí)現(xiàn)的。采用了兩種代理:JDK動態(tài)代理和CGLIB動態(tài)代理。

基本術(shù)語(一些名詞):
(1)切面(Aspect)
切面泛指[交叉業(yè)務(wù)邏輯]。事務(wù)處理和日志處理可以理解為切面。常用的切面有通知(Advice)與顧問(Advisor)。實(shí)際就是對主業(yè)務(wù)邏輯的一種增強(qiáng)。

(2)織入(Weaving)
織入是指將切面代碼插入到目標(biāo)對象的過程。代理的invoke方法完成的工作,可以稱為織入。

(3) 連接點(diǎn)(JoinPoint)
連接點(diǎn)是指可以被切面織入的方法。通常業(yè)務(wù)接口的方法均為連接點(diǎn)

(4)切入點(diǎn)(PointCut)
切入點(diǎn)指切面具體織入的方法
注意:被標(biāo)記為final的方法是不能作為連接點(diǎn)與切入點(diǎn)的。因?yàn)樽罱K的是不能被修改的,不能被增強(qiáng)的。

(5)目標(biāo)對象(Target)
目標(biāo)對象指將要被增強(qiáng)的對象。即包含主業(yè)務(wù)邏輯的類的對象。

(6)通知(Advice)
通知是切面的一種實(shí)現(xiàn),可以完成簡單的織入功能。通知定義了增強(qiáng)代碼切入到目標(biāo)代碼的時(shí)間點(diǎn),是目標(biāo)方法執(zhí)行之前執(zhí)行,還是執(zhí)行之后執(zhí)行等。切入點(diǎn)定義切入的位置,通知定義切入的時(shí)間。

(7)顧問(Advisor)
顧問是切面的另一種實(shí)現(xiàn),能夠?qū)⑼ㄖ愿鼮閺?fù)雜的方式織入到目標(biāo)對象中,是將通知包裝為更復(fù)雜切面的裝配器。

AOP是一種思想,而非實(shí)現(xiàn)
AOP是基于OOP,而又遠(yuǎn)遠(yuǎn)高于OOP,主要是將主要核心業(yè)務(wù)和交叉業(yè)務(wù)分離,交叉業(yè)務(wù)就是切面。例如,記錄日志和開啟事務(wù)。

一:前置增強(qiáng)和后置增強(qiáng)

image

源碼介紹:

1.User.java

image

View Code

2.IDao.java

image

View Code

3.UserDao.java

image

View Code

4.IUserBiz.java

image

View Code

5.UserBiz.java

image

View Code

6.LoggerAfter.java(后置增強(qiáng))

image

View Code

7.LoggerBefore.java(前置增強(qiáng))

image

View Code

8.applicationContext.xml(Spring配置文件)

image

View Code

當(dāng)然,針對AOP的配置也可以使用代理對象 ProxyFactoryBean 代理工廠bean來實(shí)現(xiàn),在測試類中:IUserBiz biz=(IUserBiz)ctx.getBean("serviceProxy");

image

View Code

9.MyTest.java

image

View Code

10.log4j.properties(日志的配置文件)

image

View Code

當(dāng)然,別忘了引入我們需要的jar包啊!

常用的jar:

image

二:異常拋出增強(qiáng)和環(huán)繞增強(qiáng)

image

源碼介紹:

1.User.java

image

View Code

2.UserService.java

image

View Code

3.ErrorLog.java(異常拋出增強(qiáng))

image

View Code

4.AroundLog(環(huán)繞增強(qiáng))

image

View Code

5.applicationContext.xml(Spring配置文件)

image

View Code

6.MyTest.java

image

View Code

三:注解增強(qiáng)方式實(shí)現(xiàn)前置增強(qiáng)和后置增強(qiáng)

image

源碼介紹:

1.UserService.java

image

View Code

2.AnnotationAdvice.java(注解增強(qiáng))

image

View Code

注:

java.lang.Object[] getArgs():獲取連接點(diǎn)方法運(yùn)行時(shí)的入?yún)⒘斜?br> Signature getSignature() :獲取連接點(diǎn)的方法簽名對象
java.lang.Object getTarget() :獲取連接點(diǎn)所在的目標(biāo)對象
java.lang.Object getThis() :獲取代理對象本身

3.applicationContext.xml(Spring配置文件)

image

View Code

4.MyTest.java

image

View Code

四: 顧問(Advisor)實(shí)現(xiàn)前置增強(qiáng)

通知Advice是Spring提供的一種切面(Aspect)。但其功能過于簡單,只能
將切面織入到目標(biāo)類的所有目標(biāo)方法中,無法完成將切面織入到指定目標(biāo)方法中。

顧問Advisor是Spring提供的另一種切面。其可以完成更為復(fù)雜的切面織入功能。PointcutAdvisor是顧問的一種,可以指定具體
的切入點(diǎn)。顧問將通知進(jìn)行了包裝,會根據(jù)不同的通知類型,在不同的時(shí)間點(diǎn),將切面織入到不同的切入點(diǎn)。
PointcutAdvisor接口有兩個(gè)較為常用的實(shí)現(xiàn)類:
:NameMatchMethodPointcutAdvisor 名稱匹配方法切入點(diǎn)顧問
:RegexpMethodPointcutAdvisor 正則表達(dá)式匹配方法切入點(diǎn)顧問
<property name="pattern" value=".
do.
"></property> 表示方法全名(包名,接口名,方法名)
運(yùn)算符 名稱 意義
. 點(diǎn)號 表示任意單個(gè)字符

  • 加號 表示前一個(gè)字符出現(xiàn)一次或者多次
  • 星號 表示前一個(gè)字符出現(xiàn)0次或者多次
    =====默認(rèn)Advisor自動代理生成器
    DefaultAdvisorAutoProxyCreator
    =====BeanName自動代理生成器
    BeanNameAutoProxyCreator

實(shí)例:

image

源碼介紹:

1.ISomeService.java

image

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">package service; //接口
public interface ISomeService { //待實(shí)現(xiàn)的方法
public void doFirst(); public void doSecond();
}</pre>

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

2.SomeServiceImpl.java

image

View Code

3.MyMethodBeforeAdvice.java

image

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">package aop; //前置增強(qiáng)
import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class MyMethodBeforeAdvice implements MethodBeforeAdvice{

@Override public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("目標(biāo)方法執(zhí)行之前執(zhí)行");
}

}</pre>

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

4.applicationContext.xml(Spring配置文件)

image

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"><?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" 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">

<!-- 目標(biāo)對象 -->
<bean id="someService" class="service.SomeServiceImpl"></bean>

<!-- 切面:通知 -->
<bean id="beforeAdvice" class="aop.MyMethodBeforeAdvice"></bean>

<!-- *********************************************** -->

<!-- 1.*:NameMatchMethodPointcutAdvisor 名稱匹配方法切入點(diǎn)顧問 -->
<!-- 切面:顧問 顧問(Advisor)要包裝通知(Advice) -->    
<bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> 
    <property name="advice" ref="beforeAdvice"></property> 
    <!--指定需要增強(qiáng)的方法:這里是doFirst()方法,而doSecond()方法則不會增強(qiáng) -->
    <property name="mappedName" value="doFirst"></property>
    <!-- 也可以使用mappedNames指定多個(gè)方法
    <property name="mappedNames" value="doFirst,doSecond"></property> -->
</bean>

<!-- *********************************************** -->

<!-- 2.*:RegexpMethodPointcutAdvisor 正則表達(dá)式匹配方法切入點(diǎn)顧問 -->
<!-- 切面: 顧問 顧問(Advisor)要包裝通知(Advice) -->
<!-- <bean id="beforeAdvisor"
    class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice" ref="beforeAdvice"></property>
    <property name="pattern" value=".*doF.*t"></property>
</bean> -->

<!-- *********************************************** -->

<!-- 代理工廠Bean -->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="someService"></property>
    <property name="interceptorNames" value="beforeAdvisor"></property>
</bean>

</beans></pre>

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

5.MyTest.java

image

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">package test; //對顧問(Advisor)測試
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import service.ISomeService; public class MyTest {
@Test public void testOne(){
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
ISomeService service = (ISomeService)ctx.getBean("serviceProxy");
service.doFirst();
service.doSecond();
}
}</pre>

[
復(fù)制代碼

](javascript:void(0); "復(fù)制代碼")

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容