Spring中基于xml的AOP的詳細(xì)步驟
1、Aop 全程是Aspect Oriented Programming 即面向切面編程,通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的同一維護(hù)的一種技術(shù)。Aop是oop的延續(xù),是軟件開發(fā)中的 一個(gè)熱點(diǎn),也是Spring框架中一個(gè)重要的內(nèi)容。是函數(shù)式編程的一個(gè)衍生范例,利用Aop可以對(duì)業(yè)務(wù)邏輯各個(gè)部分進(jìn)行分割,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用行,提高了開發(fā)效率。簡(jiǎn)單的說(shuō)就是把我們程序中的重復(fù)代碼抽取出來(lái),在需要執(zhí)行的時(shí)候,使用動(dòng)態(tài)代理的技術(shù),在不修改源碼的基礎(chǔ)上已有的方法進(jìn)行增強(qiáng),(使用動(dòng)態(tài)代理的方式實(shí)現(xiàn))
相關(guān)術(shù)語(yǔ)
JoinPoint:鏈接點(diǎn) 那些被攔截到的點(diǎn),在spring中,這些點(diǎn)指的是方法,因?yàn)閟pring只支持方法類型的連接點(diǎn)
Pointcut:切入點(diǎn) 是指我們要對(duì)哪些JoinPont進(jìn)行攔截的定義
Advice:通知/增強(qiáng) 攔截到Joinpoint之后所要做的事情就是通知
通知類型:前置通知、后置通知、異常通知、最終通知、環(huán)繞通知
Introduction:引介 是一種特殊的通知,在不修改類代碼的前提下,Introduction可以在運(yùn)行期為類動(dòng)態(tài)的添加一些方法或field
Target:目標(biāo)對(duì)象,代理的目標(biāo)對(duì)象
Weaving織入 是指把增強(qiáng)應(yīng)用到目標(biāo)對(duì)象來(lái)創(chuàng)建新的代理對(duì)象的過(guò)程,spring采用動(dòng)態(tài)代理織入,而AspectJ采用編譯期織入和類裝載期織入
Proxy:代理,一類類被Aop織入增強(qiáng)后,就產(chǎn)生一個(gè)結(jié)果代理類
Aspect:切面 是切入點(diǎn)和通知(引介)的結(jié)合
在 spring 中,框架會(huì)根據(jù)目標(biāo)類是否實(shí)現(xiàn)了接口來(lái)決定采用哪種動(dòng)態(tài)代理的方式。
基于XMl的AOP步驟
1、創(chuàng)建Maven項(xiàng)目引入spring坐標(biāo)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mingqi</groupId> <artifactId>SpringIOC</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
2、創(chuàng)建業(yè)務(wù)層接口:
package com.mingqi.services;
public interface IAccountService {
/**
* 模擬登陸賬戶
*/
void saveAccount();
/**
* 模擬更新賬戶
* @param id
*/
void updateAccount(int id);
/**
* 模擬刪除賬戶
* @return
*/
int deleteAccount();
}
3.創(chuàng)建業(yè)務(wù)層實(shí)現(xiàn)類
package com.mingqi.services.impl;
import com.mingqi.services.IAccountService;
public class AccountServicesImpl implements IAccountService {
public void saveAccount() {
System.out.println("執(zhí)行了保存");
}
public void updateAccount(int id) {
System.out.println("執(zhí)行了更新"+id);
}
public int deleteAccount() {
System.out.println("執(zhí)行了刪除");
return 0;
}
}
4、創(chuàng)建工具類
package com.mingqi.utils;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 用戶記錄日志的工具類,里面提供公共的代碼
*/
public class Logger {
/**
* 用于打印日志:計(jì)劃讓其在切入點(diǎn)方法執(zhí)行前執(zhí)行(切入點(diǎn)方法就是業(yè)務(wù)層方法)
*/
public void beforePrintLog(){
System.out.println("Logger類中的pringLog方法開始記錄日志了。。。");
}
public void afterReturningPrintLog()
{
System.out.println("后置通知Logger類中的beforePrintLog方法開始記錄日志了。。。");
}
/**
* 異常通知
*/
public void afterThrowingPrintLog()
{
System.out.println("異常通知Logger類中的afterThrowingPrintLog方法開始記錄日志了。。。");
}
/**
* 最終通知
*/
public void afterPrintLog()
{
System.out.println("最終通知Logger類中的afterPrintLog方法開始記錄日志了。。。");
}
/**
* 環(huán)繞通知
* 問(wèn)題 當(dāng)我們配置了環(huán)繞通知以后,切入點(diǎn)方法沒(méi)有執(zhí)行,而通知方法執(zhí)行了
* 分析: 通過(guò)對(duì)比動(dòng)態(tài)代理中的環(huán)繞通知代碼,發(fā)現(xiàn)動(dòng)態(tài)代理中的環(huán)繞通知有明確的切入點(diǎn)方法調(diào)用,而我們的代碼中沒(méi)有
* 解決: Spring 框架為我們提供了一個(gè)接口:ProceedingJoinPoint。該接口有一個(gè)方法proceed(),此方法就相當(dāng)于明確調(diào)用切入點(diǎn)的方法
* 該接口可以作為環(huán)繞通知的參數(shù)方法,在程序執(zhí)行時(shí),spring框架會(huì)為我們提供該接口的實(shí)現(xiàn)類供我們使用
* spring中的環(huán)繞通知
* 他是spring框架為我們提供的一種可以在代碼中手動(dòng)控制增強(qiáng)方法何時(shí)會(huì)執(zhí)行的方式
* @param pjp
* @return
*/
public Object aroundPringLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try{
Object[] args = pjp.getArgs();//得到方法執(zhí)行所需的參數(shù)
System.out.println("Logger類中的aroundPringLog方法開始記錄日志了。。。前置");
rtValue = pjp.proceed(args);//明確調(diào)用業(yè)務(wù)層方法(切入點(diǎn)方法)
System.out.println("Logger類中的aroundPringLog方法開始記錄日志了。。。后置");
return rtValue;
}catch (Throwable t){
System.out.println("Logger類中的aroundPringLog方法開始記錄日志了。。。異常");
throw new RuntimeException(t);
}finally {
System.out.println("Logger類中的aroundPringLog方法開始記錄日志了。。。最終");
}
}
}
5、創(chuàng)建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: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">
<!-- 配置spring的IOC,把service對(duì)象配置進(jìn)來(lái)-->
<bean id="accountSevice" class="com.mingqi.services.impl.AccountServicesImpl"></bean>
<!-- spring 中基于xml的Aop配置步驟
1、把通知Bean也交給spring來(lái)管理
2、使用aop:config標(biāo)簽表名開始aop的配置
3、使用aop:aspect標(biāo)簽表明配置切面
id屬性:是給切面提供一個(gè)唯一標(biāo)識(shí)
ref屬性:是指定通知類的id
4、在aop:aspect標(biāo)簽的內(nèi)部使用對(duì)應(yīng)的標(biāo)簽來(lái)配置通知的類型
我們現(xiàn)在的示例是讓printlog方法在切入點(diǎn)方法執(zhí)行之前執(zhí)行,所以是前置通知
aop:before:標(biāo)識(shí)前置通知
method屬性: 用于指定Logger類中的方法哪個(gè)是前置通知
pointcut屬性: 用于指定切入點(diǎn)表達(dá)式,該表達(dá)式的含義指的是對(duì)業(yè)務(wù)層中的哪些方法增強(qiáng)
切入點(diǎn)表達(dá)式的寫法:
關(guān)鍵字:execution(表達(dá)式)
表達(dá)式: 訪問(wèn)修飾符 返回值 包名.包名.包名....類名.方法名(參數(shù)列表)
標(biāo)準(zhǔn)的寫法: public void com.mingqi.service.impl.AccountServiceImpl.saveAccount()
訪問(wèn)修飾符可以省略:void com.mingqi.service.impl.AccountServiceImpl.saveAccount()
返回值可以使用通配符,標(biāo)識(shí)任意返回值:* com.mingqi.service.impl.AccountServiceImpl.saveAccount()
包名可以使用通配符,表示任意包,但是有幾級(jí)包就需要寫幾個(gè)* *.*.*.*.*.AccountServiceImpl.saveAccount()
包名可以使用..代表當(dāng)前包及其子包:* *.AccountServiceImpl.saveAccount()
類名和方法名都可以使用*來(lái)實(shí)現(xiàn)統(tǒng)配 * *..*.*();
參數(shù)列表: 可以直接寫數(shù)據(jù)類型:
基本類型直接寫名稱:int
引用類型寫包名.類名的方式: java.lang.String
可以使用通配符來(lái)標(biāo)識(shí)任意類型,單必須有參數(shù)
可以使用..標(biāo)識(shí)有無(wú)參數(shù)均可,有參數(shù)可以是任意類型
全通配寫法:
* *..*.*(..)
實(shí)際開發(fā)中 切入點(diǎn)表達(dá)式的通常寫法:
切到業(yè)務(wù)層實(shí)現(xiàn)類的所有方法,* com.mingqi.service.impl.*.*(..);
-->
<!-- 配置Logger類-->
<bean id="logger" class="com.mingqi.utils.Logger"></bean>
<!--使用aop:config標(biāo)簽表名開始aop的配置-->
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.mingqi.services.impl.*.*(..))"></aop:pointcut>
<!--使用aop:aspect標(biāo)簽表明配置切面-->
<aop:aspect id="LogAdvice" ref="logger">
<!-- 配置前置通知:在切入點(diǎn)方法執(zhí)行之前執(zhí)行
<aop:before method="beforePrintLog" pointcut-ref="pt1"></aop:before>-->
<!-- 配置后置通知:在切入點(diǎn)方法正常執(zhí)行之后值。它和異常通知永遠(yuǎn)只能執(zhí)行一個(gè)
<aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>-->
<!-- 配置異常通知:在切入點(diǎn)方法執(zhí)行產(chǎn)生異常之后執(zhí)行。它和后置通知永遠(yuǎn)只能執(zhí)行一個(gè)
<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>-->
<!-- 配置最終通知:無(wú)論切入點(diǎn)方法是否正常執(zhí)行它都會(huì)在其后面執(zhí)行
<aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>-->
<!-- 配置環(huán)繞通知 詳細(xì)的注釋請(qǐng)看Logger類中-->
<aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
</beans>
6、創(chuàng)建測(cè)試類
package com.mingqi.test;
import com.mingqi.services.IAccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringIoc {
@Test
public void TestAccount()
{
ApplicationContext ac= new ClassPathXmlApplicationContext("beam.xml");
IAccountService accountService=(IAccountService) ac.getBean("accountSevice");
accountService.saveAccount();
accountService.updateAccount(22);
accountService.deleteAccount();
}
}
總結(jié)
到此這篇關(guān)于Spring中基于xml的AOP的詳細(xì)步驟的文章就介紹到這了,更多相關(guān)Spring基于xml的AOP內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解BeanUtils.copyProperties()方法如何使用
這篇文章主要為大家介紹了詳解BeanUtils.copyProperties()方法如何使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
注冊(cè)中心配置了spring?security后客戶端啟動(dòng)報(bào)錯(cuò)
這篇文章主要為大家介紹了注冊(cè)中心配置了spring?security后客戶端啟動(dòng)報(bào)錯(cuò)問(wèn)題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
Java處理時(shí)間格式CST和GMT轉(zhuǎn)換方法示例
這篇文章主要給大家介紹了關(guān)于Java處理時(shí)間格式CST和GMT轉(zhuǎn)換方法的相關(guān)資料,相信很多小伙伴在時(shí)間格式轉(zhuǎn)換的時(shí)候非常頭疼,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
Eclipse下使用ANT編譯提示OutOfMemory的解決方法
由于需要使用ANT編譯的代碼比較多,特別是在第一次變異的時(shí)候,會(huì)出現(xiàn)OutOfMemory錯(cuò)誤。并提示更改ANT_OPTS設(shè)定。2009-04-04
關(guān)于Mybatis-plus設(shè)置字段為空的正確寫法
這篇文章主要介紹了關(guān)于Mybatis-plus設(shè)置字段為空的正確寫法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
在Spring中實(shí)現(xiàn)異步處理的步驟和代碼演示
在Spring中實(shí)現(xiàn)異步處理通常涉及到@Async注解,通過(guò)步驟和代碼演示,可以在Spring應(yīng)用程序中實(shí)現(xiàn)異步處理,記住要根據(jù)你的應(yīng)用程序的實(shí)際需求來(lái)調(diào)整線程池和異步方法的設(shè)計(jì),感興趣的朋友跟隨小編一起看看吧2024-06-06
SpringBoot實(shí)現(xiàn)監(jiān)控Actuator,關(guān)閉redis監(jiān)測(cè)
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)監(jiān)控Actuator,關(guān)閉redis監(jiān)測(cè),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11

