日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

Spring AOP学习

發(fā)布時(shí)間:2025/6/15 javascript 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring AOP学习 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

什么是AOP

?Spring AOP 面向切面編程,采取橫向抽取機(jī)制,取代了傳統(tǒng)縱向繼承體系重復(fù)性代碼(性能監(jiān)視、事務(wù)管理、安全檢查、緩存)

?使用純Java實(shí)現(xiàn),不需要專(zhuān)門(mén)的編譯過(guò)程和類(lèi)加載器,在運(yùn)行期通過(guò)JDK動(dòng)態(tài)代理或者CGLIB動(dòng)態(tài)代理的方式向目標(biāo)類(lèi)織入增強(qiáng)代碼

?AspectJ ?[??spekt]?是一個(gè)基于Java語(yǔ)言的AOP框架,擴(kuò)展了Java語(yǔ)言,提供了一個(gè)專(zhuān)門(mén)的編譯器,在編譯時(shí)提供橫向代碼的織入。

?

在決定使用哪種框架實(shí)現(xiàn)你的項(xiàng)目之前,有幾個(gè)要點(diǎn)(同樣適用于其他框架)。https://www.oschina.net/translate/comparative_analysis_between_spring_aop_and_aspectj

明確你在應(yīng)用橫切關(guān)注點(diǎn)(cross-cutting concern)時(shí)(例如事物管理、日志或性能評(píng)估),需要處理的是Spring beans還是POJO。

如果正在開(kāi)發(fā)新的應(yīng)用,則選擇Spring AOP就沒(méi)有什么阻力。但是如果你正在維護(hù)一個(gè)現(xiàn)有的應(yīng)用(該應(yīng)用并沒(méi)有使用Spring框架),AspectJ就將是一個(gè)自然的選擇了。

為了詳細(xì)說(shuō)明這一點(diǎn),假如你正在使用Spring AOP,當(dāng)你想將日志功能作為一個(gè)通知(advice)加入到你的應(yīng)用中,用于追蹤程序流程,那么該通知(Advice)就只能應(yīng)用在Spring beans的連接點(diǎn)(Joinpoint)之上。

另一個(gè)需要考慮的因素是,你是希望在編譯期間進(jìn)行織入(weaving),還是編譯后(post-compile)或是運(yùn)行時(shí)(run-time)。Spring只支持運(yùn)行時(shí)織入。如果你有多個(gè)團(tuán)隊(duì)分別開(kāi)發(fā)多個(gè)使用Spring編寫(xiě)的模塊(導(dǎo)致生成多個(gè)jar文件,例如每個(gè)模塊一個(gè)jar文件),并且其中一個(gè)團(tuán)隊(duì)想要在整個(gè)項(xiàng)目中的所有Spring bean(例如,包括已經(jīng)被其他團(tuán)隊(duì)打包了的jar文件)上應(yīng)用日志通知(在這里日志只是用于加入橫切關(guān)注點(diǎn)的舉例),那么通過(guò)配置該團(tuán)隊(duì)自己的Spring配置文件就可以輕松做到這一點(diǎn)。之所以可以這樣做,就是因?yàn)镾pring使用的是運(yùn)行時(shí)織入。如果你使用AspectJ想要做到同樣的事情,你也許就需要使用acj(AspectJ編譯器)重新編譯所有的代碼并且進(jìn)行重新打包。否則,你也可以選擇使用AspectJ編譯后(post-compile)或載入時(shí)(load-time)織入。

Advisor和Aspect的區(qū)別:

Advisor:Spring傳統(tǒng)意義上的切面,支持一個(gè)切點(diǎn)和一個(gè)通知的組合

Aspect:支持多個(gè)切點(diǎn)和多個(gè)通知的組合,真實(shí)開(kāi)發(fā)中常用。

為什么要用AOP

在傳統(tǒng)的面向?qū)ο缶幊虝r(shí),難免有很多重復(fù)的代碼。我們可以把重復(fù)的代碼提出來(lái),放到一個(gè)類(lèi)中,然后統(tǒng)一使用,這樣將來(lái)修改起來(lái)也會(huì)很是方便。

AOP底層原理

就是代理機(jī)制:

* 動(dòng)態(tài)代理:(JDK中使用)

* JDK的動(dòng)態(tài)代理,對(duì)實(shí)現(xiàn)了接口的類(lèi)生成代理.

Spring的AOP代理

JDK動(dòng)態(tài)代理:對(duì)實(shí)現(xiàn)了接口的類(lèi)生成代理。沒(méi)有實(shí)現(xiàn)接口的類(lèi),就無(wú)法生成代理對(duì)象了。

CGLib代理機(jī)制:對(duì)類(lèi)生成代理

代理實(shí)例:

一個(gè)接口:

package com.js.demo10;public interface Greeting {void sayHello(String name); }

一個(gè)實(shí)現(xiàn)類(lèi):

package com.js.demo10;

public
class GreetingImpl implements Greeting {@Overridepublic void sayHello(String name) {before();System.out.println("Hello! " + name);after();}private void before() {System.out.println("Before");}private void after() {System.out.println("After");} }

靜態(tài)代理實(shí)現(xiàn)實(shí)例:

由程序員創(chuàng)建或由特定工具自動(dòng)生成源代碼,再對(duì)其編譯。在程序運(yùn)行前,代理類(lèi)的.class文件就已經(jīng)存在了。

package com.js.demo10;

public
class GreetingProxy implements Greeting {private GreetingImpl greetingImpl;public GreetingProxy(GreetingImpl greetingImpl) {this.greetingImpl = greetingImpl;}@Overridepublic void sayHello(String name) {before();greetingImpl.sayHello(name);after();}private void before() {System.out.println("Before");}private void after() {System.out.println("After");} }

客戶(hù)端來(lái)調(diào)用:

public class GreetingProxyClient {public static void main(String[] args) { Greeting greetingProxy = new GreetingProxy(new GreetingImpl());greetingProxy.sayHello("Jack");} }

問(wèn)題:XxxProxy 這樣的類(lèi)會(huì)越來(lái)越多,如何才能將這些代理類(lèi)盡可能減少呢?最好只有一個(gè)代理類(lèi)。

如果項(xiàng)目中有多個(gè)類(lèi),則需要編寫(xiě)多個(gè)代理類(lèi),工作量大,不好修改,不好維護(hù),不能應(yīng)對(duì)變化。

JDK動(dòng)態(tài)代理實(shí)現(xiàn)實(shí)例:

?JDK內(nèi)置的Proxy動(dòng)態(tài)代理可以在運(yùn)行時(shí)動(dòng)態(tài)生成字節(jié)碼,而沒(méi)必要針對(duì)每個(gè)類(lèi)編寫(xiě)代理類(lèi)。

package com.js.demo10;import java.lang.reflect.Method;import org.springframework.cglib.proxy.InvocationHandler; import org.springframework.cglib.proxy.Proxy;public class JDKDynamicProxy implements InvocationHandler {private Object target;public JDKDynamicProxy(Object target) {this.target = target;}@SuppressWarnings("unchecked")public <T> T getProxy() {return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();Object result = method.invoke(target, args);after();return result;}private void before() {System.out.println("Before");}private void after() {System.out.println("After");} }

客戶(hù)端來(lái)調(diào)用:

public class JDKDynamicProxyClient {public static void main(String[] args) {Greeting greeting = new JDKDynamicProxy(new GreetingImpl()).getProxy();greeting.sayHello("Jack");} }

問(wèn)題:JDK 給我們提供的動(dòng)態(tài)代理只能代理接口,而不能代理沒(méi)有接口的類(lèi)。

CGLIB動(dòng)態(tài)代理實(shí)現(xiàn)實(shí)例:

CGLIB(Code Generation Library)是一個(gè)開(kāi)源項(xiàng)目,是一個(gè)強(qiáng)大的,高性能,高質(zhì)量的Code生成類(lèi)庫(kù),它可以在運(yùn)行期擴(kuò)展Java類(lèi)與實(shí)現(xiàn)Java接口,通俗說(shuō)cglib可以在運(yùn)行時(shí)動(dòng)態(tài)生成字節(jié)碼。

大概的原理是:使用cglib可以實(shí)現(xiàn)動(dòng)態(tài)代理,即使被代理的類(lèi)沒(méi)有實(shí)現(xiàn)接口,但被代理的類(lèi)必須不是final類(lèi)。cglib繼承被代理的類(lèi),重寫(xiě)方法,織入通知,動(dòng)態(tài)生成字節(jié)碼并運(yùn)行,因?yàn)槭抢^承所以final類(lèi)是沒(méi)有辦法動(dòng)態(tài)代理的。

package com.js.demo10;import java.lang.reflect.Method;import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy;public class CGLibDynamicProxy implements MethodInterceptor {private static CGLibDynamicProxy instance = new CGLibDynamicProxy();private CGLibDynamicProxy() {}public static CGLibDynamicProxy getInstance() {return instance;}@SuppressWarnings("unchecked")public <T> T getProxy(Class<T> cls) {return (T) Enhancer.create(cls, this);}@Overridepublic Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {before();Object result = proxy.invokeSuper(target, args);after();return result;}private void before() {System.out.println("Before");}private void after() {System.out.println("After");} }

客戶(hù)端來(lái)調(diào)用:

public class CGLibDynamicProxyClient {public static void main(String[] args) { Greeting greeting = CGLibDynamicProxy.getInstance().getProxy(GreetingImpl.class);//?Singleton 模式greeting.sayHello("Jack");} }

?

結(jié)論:Spring框架,如果類(lèi)實(shí)現(xiàn)了接口,就使用JDK的動(dòng)態(tài)代理生成代理對(duì)象,如果這個(gè)類(lèi)沒(méi)有實(shí)現(xiàn)任何接口,使用CGLIB生成代理對(duì)象.

如果項(xiàng)目中有些類(lèi)沒(méi)有實(shí)現(xiàn)接口,則不應(yīng)該為了實(shí)現(xiàn)動(dòng)態(tài)代理而刻意去抽出一些沒(méi)有實(shí)例意義的接口,通過(guò)cglib可以解決該問(wèn)題。

AOP的術(shù)語(yǔ)

Aspect(切面):是切入點(diǎn)和通知(引介)的結(jié)合,橫切關(guān)注點(diǎn)被模塊化的特殊對(duì)象。即,它是一個(gè)類(lèi)

Advice(通知/增強(qiáng)):所謂通知是指攔截到Joinpoint之后所要做的事情,即攔截邏輯.切面必須要完成的工作。即,它是類(lèi)中的一個(gè)方法

通知分為前置通知,后置通知,異常通知,最終通知,環(huán)繞通知

Target(目標(biāo)對(duì)象)代理的目標(biāo)對(duì)象

Proxy(代理):一個(gè)類(lèi)被AOP織入增強(qiáng)后,就產(chǎn)生一個(gè)結(jié)果代理類(lèi)

Joinpoint(連接點(diǎn)):所謂連接點(diǎn)是指那些被攔截到的點(diǎn)。在spring中,這些點(diǎn)指的是方法,因?yàn)閟pring只支持方法類(lèi)型的連接點(diǎn).

Pointcut(切入點(diǎn)):所謂切入點(diǎn)是指我們要對(duì)哪些Joinpoint連接點(diǎn)進(jìn)行攔截的定義,簡(jiǎn)單理解如正則表達(dá)式.

Weaving(織入):是指把增強(qiáng)應(yīng)用到目標(biāo)對(duì)象來(lái)創(chuàng)建新的代理對(duì)象的過(guò)程.

Introduction(引介):引介是一種特殊的通知在不修改類(lèi)代碼的前提下, Introduction可以在運(yùn)行期為類(lèi)動(dòng)態(tài)地添加一些屬性方法.

spring采用動(dòng)態(tài)代理織入,而AspectJ采用編譯期織入和類(lèi)裝在期織入

?

?

?

Spring按照通知Advice在目標(biāo)方法的連接點(diǎn)位置,通知Advice可分為五類(lèi)(可以分編程式和聲明式實(shí)現(xiàn))

前置通知:org.springframework.aop.MethodBeforeAdvice,在目標(biāo)方法執(zhí)行之前實(shí)施增強(qiáng)

后置通知:org.springframework.aop.AfterReturningAdvice,在目標(biāo)方法執(zhí)行之后實(shí)施增強(qiáng)

環(huán)繞通知:org.aopalliance.intercept.MethodInterceptor,在目標(biāo)方法執(zhí)行前后實(shí)施增強(qiáng)

異常拋出通知:org.springframework.aop.ThrowsAdvice,在方法拋出異常之后實(shí)施增強(qiáng)

引介通知:org.springframework.aop.IntroductionInterceptor,在目標(biāo)類(lèi)中添加一些新的方法和屬性

?

Spring中切面的類(lèi)型:

Advisor:Spring中的傳統(tǒng)切面。

Aspect:都是有一個(gè)切點(diǎn)和一個(gè)通知的組合

Advisor:多個(gè)切點(diǎn)和多個(gè)通知的組合

?

Advisor?:?代表一般切面,Advice本身就是一個(gè)切面,對(duì)目標(biāo)類(lèi)所有方法進(jìn)行攔截(*不帶有切點(diǎn)的切面)

PointcutAdvisor?:?代表具有切點(diǎn)的切面,可以指定攔截目標(biāo)類(lèi)哪些方法帶有切點(diǎn)的切面,針對(duì)某個(gè)方法進(jìn)行攔截

?IntroductionAdvisor?:?代表引介切面,針對(duì)引介通知而使用切面(不要求掌握)

不帶有切點(diǎn)的切面

不帶切點(diǎn)的切面實(shí)例

導(dǎo)入相應(yīng)的jar包:Spring開(kāi)發(fā)基礎(chǔ)包、spring-aop-4.3.7.RELEASE.jar、aopalliance-1.0.jar(AOP聯(lián)盟包)

編寫(xiě)一個(gè)接口Customer:

package com.js.aopStu;public interface CustomerDao {public void add();public void delete();public void update();public void find(); }

編寫(xiě)實(shí)現(xiàn)類(lèi)CustomerImpl:

package com.js.aopStu;public class CustomerImpl implements CustomerDao {@Overridepublic void add() { System.out.println("添加客戶(hù)...");}@Overridepublic void delete() { System.out.println("刪除客戶(hù)...");}@Overridepublic void update() { System.out.println("修改客戶(hù)...");}@Overridepublic void find() {System.out.println("查詢(xún)客戶(hù)...");}}

編寫(xiě)增強(qiáng)的代碼。新建一個(gè)類(lèi)MyBeforeAdvice,以前置增強(qiáng)為例

package com.js.aopStu;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;/*** 前置增強(qiáng)* 實(shí)現(xiàn)指定接口* @author hdb**/ public class MyBeforeAdvice implements MethodBeforeAdvice{/*** method:執(zhí)行的方法* args:參數(shù)* target:目標(biāo)對(duì)象*/@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("前置增強(qiáng)...");}}

配置代理生成代理類(lèi),基于ProxyFactoryBean類(lèi),底層自動(dòng)選擇使用JDK的動(dòng)態(tài)代理還是CGLIB的代理。

配置applicationContext.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:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" 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/util http://www.springframework.org/schema/util/spring-util.xsd"><!-- 定義目標(biāo)對(duì)象 --> <bean id="customerDao" class="com.js.aopStu.CustomerImpl"></bean> <!-- 定義增強(qiáng) --> <bean id="beforeAdice" class="com.js.aopStu.MyBeforeAdvice"></bean><!-- Spring支持配置來(lái)生成代理,基于ProxyFactoryBean類(lèi),底層自動(dòng)選擇使用JDK的動(dòng)態(tài)代理還是CGLIB的代理 --><bean id="customerDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><!-- 設(shè)置目標(biāo)對(duì)象 --><property name="target" ref="customerDao"></property><!-- 設(shè)置實(shí)現(xiàn)的接口,value中寫(xiě)接口的全路徑 --><property name="proxyInterfaces" value="com.js.aopStu.CustomerDao"></property><!-- 配置需要攔截的,一定是value,此處對(duì)customerDao中的所有方法攔截 --><property name="interceptorNames" value="beforeAdice"></property></bean></beans>

?

我們需要配置一些屬性,不需要都設(shè)置。

lProxyFactoryBean常用可配置屬性 ?target : 代理的目標(biāo)對(duì)象 ?proxyInterfaces : 代理要實(shí)現(xiàn)的接口 ?如果多個(gè)接口可以使用以下格式賦值

<list>

??? <value></value>

??? ....

</list>

?proxyTargetClass : 是否對(duì)類(lèi)代理而不是接口,設(shè)置為true時(shí),使用CGLib代理 ?interceptorNames : 需要織入目標(biāo)的Advice ?singleton : 返回代理是否為單實(shí)例,默認(rèn)為單例 ?optimize : 當(dāng)設(shè)置為true時(shí),強(qiáng)制使用CGLib (proxyInterfaces、proxyTargetClass二者互斥,不能同時(shí)存在)

編寫(xiě)測(cè)試類(lèi):

package com.js.aopStu;import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class TestAOPDemo1 {@Autowired@Qualifier("customerDaoProxy")private CustomerDao customerDao;//不使用增強(qiáng)的情況下 @Testpublic void Demo1(){customerDao.add();customerDao.delete();customerDao.find();customerDao.update();} }

帶有切點(diǎn)的切面(常用)

用PointcutAdvisor實(shí)現(xiàn)類(lèi),它有兩個(gè)接口: 1、DefaultPointcutAdvisor:最常用的切面類(lèi)型,它可以通過(guò)任意Pointcut和Advice 組合定義切面 2、RegexpMethodPointcutAdvisor:構(gòu)造正則表達(dá)式切點(diǎn)切面一般使用這種

帶有切點(diǎn)的切面實(shí)例

新建一個(gè)DAO,創(chuàng)建被代理對(duì)象:

package com.js.demo3; /*** 目標(biāo)對(duì)象* @author hdb**/ public class OrderDao {public void add() { System.out.println("添加訂單...");}public void delete() { System.out.println("刪除訂單...");}public void update() { System.out.println("修改訂單...");}public void find() {System.out.println("查詢(xún)訂單...");} }

編寫(xiě)增強(qiáng)類(lèi),這次使用環(huán)繞增強(qiáng):

package com.js.demo3;import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation;/*** 增強(qiáng)的類(lèi)* 使用的是環(huán)繞增強(qiáng)* @author hbd**/ public class MyAroundAdvice implements MethodInterceptor{@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {System.out.println("環(huán)繞前增強(qiáng)===");Object object=methodInvocation.proceed();//執(zhí)行目標(biāo)對(duì)象的方法System.out.println("環(huán)繞后增強(qiáng)===");return object;}}

生成代理:通過(guò)配置的方式:

<?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:util="http://www.springframework.org/schema/util"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/util http://www.springframework.org/schema/util/spring-util.xsd"><!-- 帶有切點(diǎn)的切面 --> <!-- 定義目標(biāo)對(duì)象 --> <bean id="orderDao1" class="com.js.demo3.OrderDao"></bean><!-- 定義增強(qiáng) --> <bean id="aroundAdvice" class="com.js.demo3.MyAroundAdvice"></bean><!-- 定義切點(diǎn)切面: --> <bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><!-- 定義表達(dá)式,規(guī)定哪些方法執(zhí)行攔截 --><!-- . 任意字符 * 任意個(gè) --><!-- <property name="pattern" value=".*"/> --><!-- <property name="pattern" value="cn\.itcast\.spring3\.demo4\.OrderDao\.add.*"/> --><!-- <property name="pattern" value=".*add.*"></property> --><property name="patterns" value=".*add.*,.*find.*"></property><!-- 應(yīng)用增強(qiáng) --><property name="advice" ref="aroundAdvice"/> </bean><!-- 定義生成代理對(duì)象 --> <bean id="orderDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><!-- 配置目標(biāo) --><property name="target" ref="orderDao1"></property><!-- 針對(duì)類(lèi)的代理 --><property name="proxyTargetClass" value="true"></property><!-- 在目標(biāo)上應(yīng)用增強(qiáng) --><property name="interceptorNames" value="myPointcutAdvisor"></property> </bean></beans>

編寫(xiě)測(cè)試類(lèi):

package com.js.demo3;import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class TestAOPDemo1 {
@Autowired@Qualifier(
"orderDaoProxy")private OrderDao orderDao;
@Test
public void demo1(){orderDao.add();orderDao.delete();orderDao.find();orderDao.update();} }

自動(dòng)代理

前面的案例中,每個(gè)代理都是通過(guò)ProxyFactoryBean織入切面代理,在實(shí)際開(kāi)發(fā)中,非常多的Bean每個(gè)都配置ProxyFactoryBean開(kāi)發(fā)維護(hù)量巨大。

自動(dòng)創(chuàng)建代理(*****基于后處理Bean.在Bean創(chuàng)建的過(guò)程中完成的增強(qiáng).生成Bean就是代理。)

(1)BeanNameAutoProxyCreator根據(jù)Bean名稱(chēng)創(chuàng)建代理

(2)DefaultAdvisorAutoProxyCreator根據(jù)Advisor本身包含信息創(chuàng)建代理

*AnnotationAwareAspectJAutoProxyCreator 基于Bean中的AspectJ 注解進(jìn)行自動(dòng)代理

之前我們手動(dòng)創(chuàng)建代理的時(shí)候,注意到一點(diǎn),都是先創(chuàng)建被代理對(duì)象,然后在創(chuàng)建代理的時(shí)候,傳入該被代理對(duì)象。

而下面要學(xué)習(xí)的兩種自動(dòng)代理,是基于后處理bean,在類(lèi)創(chuàng)建的過(guò)程中完成增強(qiáng),生成的bean,就是代理!

基于Bean名稱(chēng)的自動(dòng)代理

先清理配置文件中其他部分,留下最簡(jiǎn)潔的四個(gè)bean配置:

<?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:util="http://www.springframework.org/schema/util"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/util http://www.springframework.org/schema/util/spring-util.xsd"><!-- 定義目標(biāo)對(duì)象 --> <bean id="orderDao2" class="com.helloAOP.autoProxy.OrderDao"></bean> <bean id="customerDao2" class="com.helloAOP.autoProxy.CustomerImpl"></bean> <!-- 定義增強(qiáng) --> <bean id="aroundAdvice2" class="com.helloAOP.autoProxy.MyAroundAdvice"></bean> <bean id="beforeAdvice2" class="com.helloAOP.autoProxy.MyBeforeAdvice"></bean>
<!-- 自動(dòng)代理:按名稱(chēng)代理 基于后處理bean,后處理bean不需要配置ID--> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><property name="beanNames" value="*Dao2"/><property name="interceptorNames" value="beforeAdvice2"/> </beans>

編寫(xiě)測(cè)試類(lèi):

package com.helloAOP.autoProxy;import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestAutoProxyByName {@Testpublic void testDemo(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");OrderDao orderDao = (OrderDao)applicationContext.getBean("orderDao2");orderDao.add();orderDao.update();orderDao.delete();orderDao.find();applicationContext.close();} }

運(yùn)行測(cè)試:

?

基于AspectJ注解信息的自動(dòng)代理

先清理配置文件中其他部分,留下最簡(jiǎn)潔的四個(gè)bean配置:

<?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:util="http://www.springframework.org/schema/util"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/util http://www.springframework.org/schema/util/spring-util.xsd"><!-- 定義目標(biāo)對(duì)象 --> <bean id="orderDao3" class="com.helloAOP.autoProxy.OrderDao"></bean> <bean id="customerDao3" class="com.helloAOP.autoProxy.CustomerImpl"></bean> <!-- 定義增強(qiáng) --> <bean id="aroundAdvice3" class="com.helloAOP.autoProxy.MyAroundAdvice"></bean> <bean id="beforeAdvice3" class="com.helloAOP.autoProxy.MyBeforeAdvice"></bean> <!-- 定義一個(gè)帶有切點(diǎn)的切面 --> <bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="pattern" value=".*add.*"></property><property name="advice" ref="aroundAdvice3"></property></bean> <!-- 自動(dòng)代理:--> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean> </beans>

編寫(xiě)測(cè)試類(lèi):

package com.helloAOP.autoProxy;import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestAutoProxyByAspectJ {@Testpublic void testDemo(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");OrderDao orderDao = (OrderDao)applicationContext.getBean("orderDao3");orderDao.add();orderDao.delete();applicationContext.close();}}

運(yùn)行測(cè)試:

AspectJ方面

AspectJ [??spekt] 是一個(gè)基于Java語(yǔ)言的AOP框架 Spring2.0以后新增了對(duì)AspectJ切點(diǎn)表達(dá)式支持 @AspectJ是AspectJ1.5新增功能,通過(guò)JDK5注解技術(shù),允許直接在Bean類(lèi)中定義切面 新版本Spring框架,建議使用AspectJ方式來(lái)開(kāi)發(fā)AOP 通過(guò)配置啟用@AspectJ切面: <?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:util="http://www.springframework.org/schema/util"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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 開(kāi)啟AspectJ自動(dòng)代理--> <aop:aspectj-autoproxy/>

AspectJ表達(dá)式:

語(yǔ)法:execution(表達(dá)式)

execution(<訪(fǎng)問(wèn)修飾符>?<返回類(lèi)型><方法名>(<參數(shù)>)<異常>)

execution(“* cn.itcast.spring3.demo1.dao.*(..)”)?????? ---只檢索當(dāng)前包

execution(“* cn.itcast.spring3.demo1.dao..*(..)”)????? ---檢索包及當(dāng)前包的子包.

execution(* cn.itcast.dao.GenericDAO+.*(..))?????????? ---檢索GenericDAO及子類(lèi)

?

AspectJ增強(qiáng):

@Before 前置通知,相當(dāng)于BeforeAdvice

@AfterReturning 后置通知,相當(dāng)于AfterReturningAdvice

@Around 環(huán)繞通知,相當(dāng)于MethodInterceptor

@AfterThrowing 拋出通知,相當(dāng)于ThrowAdvice

@After 最終final通知,不管是否異常,該通知都會(huì)執(zhí)行

@DeclareParents 引介通知,相當(dāng)于IntroductionInterceptor (不要求掌握)

下面詳細(xì)介紹詳細(xì)的使用方法(基于注解、基于XML),并做舉例說(shuō)明。

基于AspectJ的注解開(kāi)發(fā)

第一步:引入相應(yīng)jar包

使用AspectJ需要導(dǎo)入SpringAOP和AspectJ相關(guān)jar包:

1、spring-aop-3.2.7.RELEASE.jar

2、aopalliance-1.0.jar

3、spring-aspects-3.2.7.RELEASE.jar

4、aspectj.weaver-1.6.8.jar

第二步:編寫(xiě)被增強(qiáng)的類(lèi),即目標(biāo)類(lèi)

package com.js.demo8; /*** 目標(biāo)類(lèi)* @author hdb**/ public class UserDao {public void add(){System.out.println("add...");}public int update(){System.out.println("update...");return 1;}public void delete(){System.out.println("delete...");}public void find(){System.out.println("find...");int d=1/0; } }

第三步:編寫(xiě)切面類(lèi),即切點(diǎn)和增強(qiáng)的結(jié)合

package com.js.demo8;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut;/*** 切面類(lèi):就是切點(diǎn)與增強(qiáng)的結(jié)合* @Aspect:用于定義切面* @Before:用于定義xx增強(qiáng),只使用其value屬性時(shí),value可以省略,其值為表達(dá)式* 表示你想對(duì)哪些類(lèi)進(jìn)行增強(qiáng),可精確到某包、某類(lèi)、某方法,控制靈活* @author hdb**/@Aspect public class MyAspect {@Before(value="execution(* com.js.demo8.UserDao.add(..))")public void before(){System.out.println("前置增強(qiáng)===");}@AfterReturning(value="execution(* com.js.demo8.UserDao.update(..))")public void afterReturnin(){System.out.println("后置增強(qiáng)===");}@Around(value="execution(* com.js.demo8.UserDao.update(..))")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{System.out.println("環(huán)繞前增強(qiáng)===");Object object=proceedingJoinPoint.proceed(); //調(diào)用目標(biāo)方法System.out.println("環(huán)繞后增強(qiáng)===");return object;}@AfterThrowing(value="MyAspect.myPointcut()",throwing="e")public void afterThrowing(Throwable e){System.out.println("不好了,出異常了==="+e.getMessage());}@After(value="MyAspect.myPointcut()")public void after(){System.out.println("最終通知===");}@Pointcut("execution(* com.js.demo1.UserDao.find(..))")private void myPointcut(){}}

關(guān)于切點(diǎn)的注解,切點(diǎn)是我們的增強(qiáng)最重要應(yīng)用的方法。為什么要定義一個(gè)切點(diǎn)呢?因?yàn)槲覀兩鲜鲩_(kāi)發(fā)中,很多通知的value表達(dá)式都是重復(fù)的,在實(shí)際開(kāi)發(fā)中,每寫(xiě)一個(gè)通知,就要去寫(xiě)一個(gè)表達(dá)式,很繁瑣。所以我們可以采用定義切點(diǎn)的方式來(lái)解決。例如上面的定義一個(gè)myPointcut切點(diǎn),可以重復(fù)調(diào)用

@Pointcut("execution(* com.js.demo1.UserDao.find(..))")private void myPointcut(){}

第四步:在applicationContext.xml中引入約束,配置bean,并開(kāi)啟自動(dòng)代理

<?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:util="http://www.springframework.org/schema/util"
    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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 開(kāi)啟AspectJ自動(dòng)生成代理,底層就是AnnotationAwareAspectJAutoProxyCreator--> <aop:aspectj-autoproxy/> <bean id="userDao" class="com.js.demo8.UserDao"></bean> <bean id="myAspect" class="com.js.demo8.MyAspect"></bean> </beans>

第五步:編寫(xiě)測(cè)試類(lèi)

package com.js.demo8;/*** 測(cè)試類(lèi)*/ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class TestAspectDemo {@Autowired@Qualifier("userDao")private UserDao userDao; @Testpublic void demo1(){userDao.add();userDao.delete();userDao.find();userDao.update();} }

第六步:運(yùn)行測(cè)試,查看結(jié)果。

基于AspectJ的XML配置方式開(kāi)發(fā)

第一步:引入相應(yīng)jar包

使用AspectJ需要導(dǎo)入SpringAOP和AspectJ相關(guān)jar包:

1、spring-aop-3.2.7.RELEASE.jar

2、aopalliance-1.0.jar

3、spring-aspects-3.2.7.RELEASE.jar

4、aspectj.weaver-1.6.8.jar

第二步:編寫(xiě)被增強(qiáng)的類(lèi),即目標(biāo)類(lèi)

package com.js.demo9;public class ProductDao {public void add(){System.out.println("add...");}public void update(){System.out.println("update...");}public void delete(){System.out.println("delete...");
     int a = 1/0;}
public String find(){System.out.println("find...");return "find Success!";} }

第三步:編寫(xiě)切面類(lèi),即切點(diǎn)和增強(qiáng)的結(jié)合

package com.js.demo9;import org.aspectj.lang.ProceedingJoinPoint;/*** 切面類(lèi)* @author hdb**/ public class MyAspectXML {public void before(){System.out.println("前置通知===");}public void after(Object returnVal){System.out.println("后置通知===返回值:"+returnVal);}public Object around(ProceedingJoinPoint point) throws Throwable{System.out.println("環(huán)繞前通知===");Object object = point.proceed();System.out.println("環(huán)繞后通知===");return object;}public void afterthrowing(Throwable e){System.out.println("糟糕,出錯(cuò)了===錯(cuò)誤信息:"+e.getMessage());}public void afterFinal(){System.out.println("最終通知===");} }

?第四步:在applicationContext.xml中引入約束,配置bean,并開(kāi)啟自動(dòng)代理

<?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:util="http://www.springframework.org/schema/util"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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 定義被增強(qiáng)的類(lèi) --> <bean id="productDao" class="com.js.demo9.ProductDao"> </bean> <!-- 定義切面類(lèi) --> <bean id="myAspectXML" class="com.js.demo9.MyAspectXML"></bean> <!-- 定義aop的配置 --> <aop:config> <!-- 定義切點(diǎn) --> <aop:pointcut expression="execution(* com.js.demo9.ProductDao.add(..))" id="myPointcut"/> <aop:pointcut expression="execution(* com.js.demo9.ProductDao.find(..))" id="myAfter"/> <aop:pointcut expression="execution(* com.js.demo9.ProductDao.update(..))" id="myAround"/>
<aop:pointcut expression="execution(* com.js.demo9.ProductDao.delete(..))" id="myafterthrowing"/> <aop:aspect ref="myAspectXML">

<!-- 前置通知 -->
<aop:before method="before" pointcut-ref="myPointcut"/>
<!-- 后置通知 -->
<aop:after-returning method="after" pointcut-ref="myAfter" returning="returnVal"/>
<!-- 環(huán)繞通知 -->
<aop:around method="around" pointcut-ref="myAround"/>

  <!-- 異常通知 --><aop:after-throwing method="afterthrowing" pointcut-ref="myAfter" throwing="e"/><!-- 最終通知 --><aop:after method="afterFinal" pointcut-ref="myAfter"/> </aop:aspect> </aop:config></beans>

第五步:編寫(xiě)測(cè)試類(lèi)

package com.js.demo9;import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class TestAspectXML {@Autowired@Qualifier("productDao")private ProductDao productDao;@Testpublic void demo(){productDao.add();productDao.find();productDao.update();productDao.delete();} }

第六步:運(yùn)行測(cè)試,查看結(jié)果。

?參考鏈接:https://blog.csdn.net/dove_knowledge/article/category/6818451

     https://my.oschina.net/pingpangkuangmo/blog/517340

    ? ??https://my.oschina.net/huangyong/blog/161338

? ? ? ? ? ? ? ? ??https://www.cnblogs.com/best/p/5736422.html

轉(zhuǎn)載于:https://www.cnblogs.com/huangdabing/p/9484349.html

總結(jié)

以上是生活随笔為你收集整理的Spring AOP学习的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。