Java的Spring框架中AOP項(xiàng)目的一般配置和部署教程
0.關(guān)于AOP
面向切面編程(也叫面向方面編程):Aspect Oriented Programming(AOP),是軟件開發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容。利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開發(fā)的效率。
AOP是OOP的延續(xù)。
主要的功能是:日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等等。
主要的意圖是:將日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等代碼從業(yè)務(wù)邏輯代碼中劃分出來,通過對(duì)這些行為的分離,我們希望可以將它們獨(dú)立到非指導(dǎo)業(yè)務(wù)邏輯的方法中,進(jìn)而改變這些行為的時(shí)候不影響業(yè)務(wù)邏輯的代碼。
可以通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)在不修改源代碼的情況下給程序動(dòng)態(tài)統(tǒng)一添加功能的一種技術(shù)。AOP實(shí)際是GoF設(shè)計(jì)模式的延續(xù),設(shè)計(jì)模式孜孜不倦追求的是調(diào)用者和被調(diào)用者之間的解耦,提高代碼的靈活性和可擴(kuò)展性,AOP可以說也是這種目標(biāo)的一種實(shí)現(xiàn)。
在Spring中提供了面向切面編程的豐富支持,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級(jí)服務(wù)(例如審計(jì)(auditing)和事務(wù)(transaction)管理)進(jìn)行內(nèi)聚性的開發(fā)。應(yīng)用對(duì)象只實(shí)現(xiàn)它們應(yīng)該做的——完成業(yè)務(wù)邏輯——僅此而已。它們并不負(fù)責(zé)(甚至是意識(shí))其它的系統(tǒng)級(jí)關(guān)注點(diǎn),例如日志或事務(wù)支持。
1.通過PropertyPlaceholderConfigurer在Spring中加載其他外部配置文件或者屬性文件:
在很多javaEE工程中,Spring的角色非常重要,是一個(gè)管理其他模塊和組件的輕量級(jí)容器,Spring經(jīng)常需要管理Struts、Ibatis、Hibernate等,這些開源框架的配置文件就通過Spring的PropertyPlaceholderConfigurer加載在Spring中進(jìn)行管理,另外,數(shù)據(jù)庫連接信息、JNDI連接信息屬性文件等也可以通過PropertyPlaceholderConfigurer加載到Spring中來管理。用法如下:
(1).通過PropertyPlaceholderConfigurer將其他文件加載到Spring中:
在spring配置文件中添加如下配置:
<bean class=“org.springframework.beans.factory.config.PropertyPlaceholderConfigurer“> <property name=“l(fā)ocations“> <value>classpath:要加載的文件名</value> …… </property> </bean>
(2).經(jīng)過(1)中的配置要加載的配置或?qū)傩晕募捅患虞d到spring中,如果還需要在運(yùn)行時(shí)使用加載進(jìn)來的配置或數(shù)據(jù)文件的一些信息,如使用數(shù)據(jù)庫連接信息或者JNDI連接信息時(shí),就可以使用類型EL表達(dá)式的語法進(jìn)行引用,例如:
<bean id=”dataSource” destroy-method=”close” class=”org.apache.common.dbcp.BasicDataSource”> <!--假設(shè)數(shù)據(jù)庫連接信息寫在外部屬性文件中,已經(jīng)被spring加載--> <property name=”driverClassName” value=”${driver}”/> <property name=”url” value=”${url}”/> <property name=”username” value=”${username}”/> <property name=”password” value=”${password}”/> </bean>
注意:也可以使用<context:Property-Placeholderlocation=”classpath:要加載的文件名”/>
2.Java的動(dòng)態(tài)代理:
Spring的面向切面編程(AOP)底層實(shí)現(xiàn)原理是動(dòng)態(tài)代理,因此在學(xué)習(xí)面向切面編程之前必須先了解動(dòng)態(tài)代理。
Java中動(dòng)態(tài)代理應(yīng)用非常廣泛,動(dòng)態(tài)代理是23中設(shè)計(jì)模式中非常常用的經(jīng)典設(shè)計(jì)模式之一。動(dòng)態(tài)代理的原理是,當(dāng)要調(diào)用一個(gè)目標(biāo)對(duì)象或者其方法時(shí),系統(tǒng)并不是直接返回目標(biāo)對(duì)象,而是返回一個(gè)代理對(duì)象,通過這個(gè)代理對(duì)象去訪問目標(biāo)對(duì)象或者目標(biāo)對(duì)象的方法。
動(dòng)態(tài)代理的簡(jiǎn)單原理如下:
客戶端調(diào)用者——>代理對(duì)象——>被調(diào)用的目標(biāo)對(duì)象。
當(dāng)客戶端調(diào)用代理對(duì)象時(shí),代理對(duì)象委派目標(biāo)對(duì)象調(diào)用其業(yè)務(wù)方法。
動(dòng)態(tài)代理分為兩種,針對(duì)接口的動(dòng)態(tài)代理和針對(duì)普通類的動(dòng)態(tài)代理,java中的動(dòng)態(tài)代理是真的接口的動(dòng)態(tài)代理,cglib是針對(duì)普通類的動(dòng)態(tài)代理,目標(biāo)javaEE的依賴包和Spring的jar包中已經(jīng)包含了cglib相關(guān)jar包,因此即可以對(duì)代理也可以對(duì)普通類進(jìn)行動(dòng)態(tài)代理。
(1).java的針對(duì)接口動(dòng)態(tài)代理:
Java中的動(dòng)態(tài)代理只能針對(duì)接口進(jìn)行動(dòng)態(tài)代理,因此,目標(biāo)對(duì)象必須實(shí)現(xiàn)接口,代理對(duì)象要實(shí)現(xiàn)目標(biāo)對(duì)象的所有接口。工作流程如下:
a.動(dòng)態(tài)代理類編寫:
注意:動(dòng)態(tài)代理必須實(shí)現(xiàn)InvocationHandler接口,同時(shí)實(shí)現(xiàn)以下方法:
Object invoke(Objectm代理實(shí)例,Method代理實(shí)例上調(diào)用的接口方法的Method 實(shí)例,Object[] 傳入代理實(shí)例上方法調(diào)用的參數(shù)值的對(duì)象數(shù)組);
安裝JDK的文檔說明,該方法作用是傳遞代理實(shí)例、識(shí)別調(diào)用方法的 java.lang.reflect.Method 對(duì)象以及包含參數(shù)的 Object 類型的數(shù)組。調(diào)用處理程序以適當(dāng)?shù)姆绞教幚砭幋a的方法調(diào)用,并且它返回的結(jié)果將作為代理實(shí)例上方法調(diào)用的結(jié)果返回。
b.創(chuàng)建代理對(duì)象:
Proxy.newProxyInstance(類加載器, Class<?>[]接口數(shù)組,回調(diào)代理對(duì)象(一般是this))
當(dāng)調(diào)用目標(biāo)對(duì)象方法時(shí),通過該方法創(chuàng)建目標(biāo)對(duì)象的代理對(duì)象,代理對(duì)象會(huì)自動(dòng)調(diào)用其invoke方法調(diào)用目標(biāo)對(duì)象,并將調(diào)用結(jié)果返回。
(2).cglib針對(duì)普通java類動(dòng)態(tài)代理:
cglib創(chuàng)建動(dòng)態(tài)代理時(shí),不要求目標(biāo)類必須實(shí)現(xiàn)接口,其工作流程如下:
a.動(dòng)態(tài)代理類編寫:
Enhancer enhancer = new Enhancer(); //設(shè)置目標(biāo)類的父類為其本身 enhancer.setSuperclass(目標(biāo)類對(duì)象.getClass()); //設(shè)置回調(diào)對(duì)象為動(dòng)態(tài)代理對(duì)象本身 enhancer.setCallback(this);
b.實(shí)現(xiàn)MethodInterceptor接口:
實(shí)現(xiàn)以下方法:
Object intercept(Objectm代理實(shí)例,Method代理實(shí)例上調(diào)用的接口方法的Method 實(shí)例,Object[] 傳入代理實(shí)例上方法調(diào)用的參數(shù)值的對(duì)象數(shù)組,MethodProxy 方法代理實(shí)例);
注意:cglib不但可以針對(duì)類動(dòng)態(tài)代理,還可以針對(duì)方法動(dòng)態(tài)代理。
3.面向切面編程(AOP)的基礎(chǔ)概念:
以一個(gè)普通的java方法來舉例
public 返回類型 方法名(參數(shù)列表){ ——>環(huán)繞通知 方法前處理代碼 ——> 前置通知 try{ 方法具體實(shí)現(xiàn)(方法體)……. 方法后處理代碼 ——> 后置通知 }Catch(異常類型 e){ 異常處理…… ——> 例外通知 }finally{ 最后處理代理…… ——> 最終通知 } }
a. 橫切關(guān)注點(diǎn):如上面5個(gè)通知的位置,在java對(duì)象中,可以這些具有類似共同處理邏輯的位置加入如權(quán)限驗(yàn)證、事物處理、日志記錄等處理邏輯的對(duì)象稱為橫切關(guān)注點(diǎn),面向?qū)ο缶幊?OOP)的關(guān)注點(diǎn)是縱向?qū)F(xiàn)實(shí)世界的事物抽象成編程的對(duì)象模型。而面向切面編程(AOP)的關(guān)注點(diǎn)是橫向的,它將編程對(duì)象模型中擁有類似處理邏輯的地方抽象出來形成切面,而編程對(duì)象中的處理邏輯就是橫切關(guān)注點(diǎn)。
b. 切面(Aspect):將橫切關(guān)注點(diǎn)抽象就形成切面,與類類似,二者關(guān)注點(diǎn)不同,類是事物特性的抽象,切面是橫切關(guān)注點(diǎn)的抽象。
c. 連接點(diǎn)(Joinpoint):被攔截到的點(diǎn),在Spring中指方法,因?yàn)閟pring只支持方法類型的連接點(diǎn),即被攔截的方法。如上面例子的方法。
d. 切入點(diǎn)(Pointcut):指對(duì)連接點(diǎn)進(jìn)行攔截的定義,是連接點(diǎn)的集合,即一系列被攔截方法的集合。
e. 通知(Advice):指攔截到連接點(diǎn)之后要做的事情,即攔截之后的邏輯處理。通常的權(quán)限驗(yàn)證、事物處理、日志記錄等操作就是在通知中定義和完成的。
f. 目標(biāo)對(duì)象(Target):代理的目標(biāo)對(duì)象,即被攔截的對(duì)象。如上面例子中方法所在的對(duì)象。
g. 織入(Weave):指將切面應(yīng)用到目標(biāo)對(duì)象,并導(dǎo)致代理對(duì)象創(chuàng)建的過程。
h. 引入(Introduction):在不修改代碼的前提下,引入可以在運(yùn)行期為類動(dòng)態(tài)的添加一些方法和字段。
4. Spring中支持面向切面編程(AOP)的依賴包:
Spring解壓后目錄中的如下3個(gè)包:
lib/aspectj/aspectjweaver.jar lib/aspectj/aspectjrt.jar lib/cglib/cglib-nodep-2.1-3.jar
5. 在spring中使用面向切面編程(AOP)時(shí),需要在spring配置文件中引入aop的命名空間,即添加如下的配置:
xmlns:aop=”http://www.springframework.org/schema/aop” “http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd”
注意:Spring2.5以后提供兩種AOP方法,即基于xml配置文件方式和基于java注解方式。
若要使用注解方式的aop,需要在spring配置文件中添加如下的對(duì)象注解方式aop的支持:
<aop:aspectj-autoProxy/>
6. JavaBean的包裝類——BeanWrapper:
Spring通過BeanWrapper類封裝一個(gè)javabean的行為,可以設(shè)置和獲取其屬性值,如:
BeanWrapper 包裝類對(duì)象 = BeanWrapperImpl(new 被包裝類()); 包裝類對(duì)象.setPropertyValue(“屬性名”,”屬性值”);
通過這種方法就可以給被包裝類設(shè)置屬性。
7. 基于注解方式的面向切面編程(AOP)開發(fā):
(1).在spring配置文件中加入對(duì)注解方法的aop支持。
(2).定義切面:
和創(chuàng)建普通類類似,在類前加上”@Aspect”注解,表明該類是一個(gè)切面。
(3).在切面中加入切入點(diǎn):
切入點(diǎn)就是被攔截對(duì)象方法的集合,通常切入點(diǎn)定義在切面中某個(gè)對(duì)切入點(diǎn)進(jìn)行處理的方法上。使用”@Pointcut”注解,語法如下:
@Pointcut(“execution(* com.test.service..*.*(..))”) public void anyMethod(){//方法名為切入點(diǎn)名 切入點(diǎn)處理 }
語法參數(shù)詳解:
a. 第一個(gè)”*”:表示被攔截的方法是任意的返回類型。
b. com.test.service:這里是舉一個(gè)簡(jiǎn)單的例子,表示要被攔截的包名,即被攔截的包。
c.被攔截包名后面的兩個(gè)”..”:表示被攔截包下面的子包也遞歸進(jìn)行攔截,即被攔截的子包。
d. ”..”之后的”*”:表示被攔截包及其子包下面的所有類,即被攔截的類。
e. 最后一個(gè)”*”:表示被攔截類中的所有方法,即被攔截的方法。
f. ”(..)”:表示被攔截的方法接收任意的參數(shù),即被攔截的參數(shù)。
注意:切入點(diǎn)定義語法可以支持通配符,但是一定要嚴(yán)格遵循語法規(guī)則。如:
@Pointcut(“execution(*com.test.service..*.add*(..))”)
表示對(duì)com.test.service包及其子包下所有的類中以”add”開頭的方法進(jìn)行攔截。
(4).在切面中添加通知:
Spring中通知位置請(qǐng)參看3中的小例子。
”@Before”注解:聲明前置通知。
“@AfterRutruning”注解:聲明后置通知。
“@After”注解:聲明最終通知。
“@AfterThrowing”注解:聲明例外通知。
“@Around”注解:聲明環(huán)繞通知。
一個(gè)定義通知的例子如下:
@Before(“anyMethod()(切面中聲明的切入點(diǎn)名)”) public void doAccessCheck(){ …… }
注意:環(huán)繞通知和其他4種通知的稍有不同,環(huán)繞通知的定義方式比較特別,環(huán)繞通知在整個(gè)方法調(diào)用前后都會(huì)起作用,因此必須使用連接點(diǎn)對(duì)象告訴連接點(diǎn)在環(huán)繞通知處理之后繼續(xù)其邏輯處理。其定義方式如下:
@Around(切入點(diǎn)名) public Object doBasicProfiling(ProcedingJoinPoint pjp) throws Throwable{ …… return pjp.proceed();//該句是告訴連接點(diǎn)繼續(xù)執(zhí)行其他的操作 }
8.基于注解方式的面向切面編程(AOP)開發(fā)的一些小技巧:
(1).獲取輸入?yún)?shù):
如:
@Before(“切入點(diǎn)名 && args(輸入?yún)?shù)名)”) public void doSomething(String 輸入?yún)?shù)名){……}
(2).獲取返回結(jié)果:
如:
@AfterReturning(Pointcut=”切入點(diǎn)名”,returning=”返回結(jié)果名”) public void dosomething(String 結(jié)果名){……}
9.基于XML方式的面向切面編程(AOP)開發(fā):
(1).定義切面類,在切面類中添加通知。
(2).將切面類想普通java類一樣在spring配置文件中配置。
(3).在spring配置文件中添加AOP配置如下:
<aop:config> <!--配置切面--> <aop:aspect id=”切面id” ref=”spring配置文件中切面類的id”> <!--配置切入點(diǎn)--> <aop:pointcut id=”切入點(diǎn)id” expression=”execution(* com.test.service..*.*(..))”/> <!--配置通知--> <aop:before pointcut-ref=”切入點(diǎn)id” method=”切面類中相應(yīng)的處理方法”/> <aop:after ……/> …… </aop:aspect> </aop:config>
10. Spring的事務(wù)處理(Spring的聲明式事務(wù)處理):
事務(wù)簡(jiǎn)單來說是指數(shù)據(jù)庫中的一條最基本的操作,關(guān)于事務(wù)的詳細(xì)講解以后會(huì)在數(shù)據(jù)庫相關(guān)總結(jié)中具體說明。Spring的面向切面編程(AOP)一個(gè)最重要的應(yīng)用是事務(wù)管理,Spring2.5以后版本的事務(wù)管理支持基于注解的方式和基于XML文件的方式兩種:
(1).基于注解方式的事務(wù)管理:
a. 在spring配置文件中添加事務(wù)管理的命名空間如下:
xmlns:ts=http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
b. 在spring配置文件中配置事務(wù)管理器如下:
<bean id=”txManager” class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”> <property name=”dataSource” ref=”spring中配置的數(shù)據(jù)源bean的id”/> </bean>
c.在spring配置文件中添加支持注解方式的事務(wù)配置項(xiàng)如下:
<tx:annotation-driventransaction-managertx:annotation-driventransaction-manager=”txManager(spring中配置的事務(wù)管理器bean的id)”/>
d.使用基于注解的事務(wù)管理:
在Spring所管理的JavaEE工程中,需要使用事務(wù)的業(yè)務(wù)邏輯地方加上“@Transactional”注解。
(2).基于XML文件方式的事務(wù)管理:
a. 在spring配置文件中配置事務(wù)管理器如下:
<bean id=”txManager” class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”> <property name=”dataSource” ref=”spring中配置的數(shù)據(jù)源bean的id”/> </bean>
b.在spring配置文件中添加事物管理的切面如下:
<aop:config> <!--配置事務(wù)切入點(diǎn)--> <aop:pointcut id=”transactionPointcut” Expression=”execution(* com.test.service..*.*(..))”/> <!--配置事務(wù)通知--> <aop:advisor advice-ref=”txAdvice” pointcut-ref=”transactionPointcut”/> </aop:config>c.在spring配置文件中為事務(wù)通知添加事物處理特性如下:
<tx:advice id=”txAdvice” transactionManager=”txManager”> <tx:attributes> <!--這里舉例將以get開頭的查詢方法設(shè)置為只讀,不支持事務(wù)--> <tx:method name=”get*” read-only=”true” propagation=”NOT_SUPPORTED”/> <!--其他的方法設(shè)置為spring默認(rèn)的事物行為--> <tx:method name=”*”/> </tx:attributes> </tx:advice>
- Java springboot項(xiàng)目jar發(fā)布過程解析
- 使用Spring Boot搭建Java web項(xiàng)目及開發(fā)過程圖文詳解
- IDEA2020.1啟動(dòng)SpringBoot項(xiàng)目出現(xiàn)java程序包:xxx不存在
- Springboot項(xiàng)目javax.validation使用方法詳解
- 在IDEA中搭建最小可用SpringMVC項(xiàng)目(純Java配置)
- 基于javamelody監(jiān)控springboot項(xiàng)目過程詳解
- Java項(xiàng)目開啟遠(yuǎn)程調(diào)試的方法步驟(tomcat、springboot)
- JavaWeb項(xiàng)目中springmvc和tomcat對(duì)靜態(tài)文件的處理
- 手把手教你怎么創(chuàng)建spring項(xiàng)目
相關(guān)文章
Java AOP動(dòng)態(tài)代理詳細(xì)介紹
AOP是一種設(shè)計(jì)思想,是軟件設(shè)計(jì)領(lǐng)域中的面向切面編程,它是面向?qū)ο缶幊痰囊环N補(bǔ)充和完善。本文將用Java實(shí)現(xiàn)AOP代理的三種方式,需要的可以參考一下2022-08-08如何使用stream從List對(duì)象中獲取某列數(shù)據(jù)
這篇文章主要介紹了如何使用stream從List對(duì)象中獲取某列數(shù)據(jù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12Java長(zhǎng)度不足左位補(bǔ)0的3種實(shí)現(xiàn)方法
這篇文章主要介紹了Java長(zhǎng)度不足左位補(bǔ)0的3種實(shí)現(xiàn)方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12IDEA SpringBoot 項(xiàng)目配置Swagger2的詳細(xì)教程
這篇文章主要介紹了IDEA SpringBoot 項(xiàng)目配置Swagger2的詳細(xì)教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11Spring boot攔截器實(shí)現(xiàn)IP黑名單的完整步驟
這篇文章主要給大家介紹了關(guān)于Spring boot攔截器實(shí)現(xiàn)IP黑名單的完整步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring boot攔截器具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06Mybatis 自動(dòng)映射(使用需謹(jǐn)慎)
這篇文章主要介紹了Mybatis 自動(dòng)映射(使用需謹(jǐn)慎),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10基于Java HttpClient和Htmlparser實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲代碼
這篇文章主要介紹了基于Java HttpClient和Htmlparser實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲代碼的相關(guān)資料,需要的朋友可以參考下2015-12-12