關(guān)于Spring AOP的理解
AOP為Aspect Oriented Programming的縮寫(xiě) :面向切面編程锋边, AOP是OOP的延續(xù) AOP并不是一種技術(shù),只是一種思想险胰,即面向切面編程的思想
在開(kāi)發(fā)中日志的使用時(shí)很頻繁的捌臊,下面就來(lái)用AOP來(lái)解決一下開(kāi)發(fā)中的日志輸出的問(wèn)題
@Service
public class TestService {
public int sum(int a ,int b ){
System.out.println("參數(shù)為:"+a+"+"+b);
int sum = a+b;
System.out.println("結(jié)果為:"+sum);
return sum;
}
}
@Autowired
private TestService testService;
@Test
void contextLoads() {
testService.sum(1,2);
}
參數(shù)為:1+2
結(jié)果為:3
在不使用aop的情況下豁鲤,我們打印日志要這樣寫(xiě)或链,這樣寫(xiě)的話就是業(yè)務(wù)代碼跟日志輸出都寫(xiě)在了一起惫恼,使得代碼冗余,而且在后面假如說(shuō)澳盐,不需要將參數(shù)輸出到日志中了祈纯,這樣需要一個(gè)類(lèi)一個(gè)類(lèi)的修改代碼,工作量時(shí)很大的
AOP就很方便簡(jiǎn)單的解決了這個(gè)問(wèn)題
AOP的理解
這是之前的日志輸出方法
這個(gè)時(shí)使用AOP的日志輸出方法
其實(shí)AOP叼耙,面向切面很好理解腕窥,就是在一個(gè)類(lèi)上橫切一刀,將我們需要的代碼切入筛婉,并且不影響之前代碼的執(zhí)行簇爆,實(shí)現(xiàn)了解耦
AOP的優(yōu)點(diǎn)
1、面向切面編程使得每個(gè)關(guān)注點(diǎn)都集中于一個(gè)地方而不是分散在多處代碼中爽撒,便于后期的統(tǒng)一維護(hù)管理冕碟。
2、服務(wù)模塊更簡(jiǎn)潔匆浙,它們只包含主要關(guān)注點(diǎn),而次要關(guān)注點(diǎn)的代碼被轉(zhuǎn)移到切面中了厕妖。
3首尼、對(duì)原方法進(jìn)行方法增強(qiáng),且不影響原方法的正常使用。
4软能、使用簡(jiǎn)單可插拔的配置迎捺,在實(shí)際邏輯執(zhí)行之前、之后或周?chē)鷦?dòng)態(tài)添加橫切關(guān)注點(diǎn)查排。
AOP的術(shù)語(yǔ)
名稱(chēng) | 描述 |
---|---|
切面(Aspect) | 切面是通知和切點(diǎn)的結(jié)合 |
通知(Advice) | 通知定義了切面是什么以及何時(shí)使用凳枝。除了描述切面要完成的工作,通知還解決了何時(shí)執(zhí)行這個(gè)工作的問(wèn)題 |
切點(diǎn)(Pointcut) | 切點(diǎn)定義了在何處工作跋核,也就是真正被切入的地方岖瑰,也就是在哪個(gè)方法應(yīng)用通知 |
連接點(diǎn)(Join point) | 連接點(diǎn)是在應(yīng)用執(zhí)行過(guò)程中能夠插入切面的一個(gè)點(diǎn) |
引入(Introduction) | 引入讓一個(gè)切面可以聲明被通知的對(duì)象實(shí)現(xiàn)了任何他們沒(méi)有真正實(shí)現(xiàn)的額外接口,而且為這些對(duì)象提供接口的實(shí)現(xiàn) |
織入(Weaving) | 織入是把切面應(yīng)用到目標(biāo)對(duì)象并創(chuàng)建新的代理對(duì)象的過(guò)程 |
其中在Spring中有5中通知類(lèi)型
名稱(chēng) | 描述 |
---|---|
前置通知(Before) | 在目標(biāo)方法被調(diào)用之前調(diào)用 |
后置通知(After) | 在目標(biāo)方法完成之后調(diào)用 |
返回通知(After-returning) | 在目標(biāo)方法成功執(zhí)行之后調(diào)用 |
異常通知(After-throwing) | 在目標(biāo)方法拋出異常后調(diào)用 |
環(huán)繞通知(Around) | 通知包裹了被通知的方法砂代,可同時(shí)定義前置通知和后置通知 |
SpringBoot 實(shí)現(xiàn)AOP
新建一個(gè)SpringBoot項(xiàng)目
-
導(dǎo)入依賴(lài)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency>
-
AOP的實(shí)現(xiàn)需要進(jìn)行配置蹋订,在Spring 中使用的時(shí)xm的方式進(jìn)行配置,但是在SpringBoot中取消了xml刻伊,改為使用了配置類(lèi)進(jìn)行配置
package com.mango.Aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * @Author: * @Date: * @Component 被Spring管理 * @Aspect 聲明他是一個(gè)aop的類(lèi) */ @Component @Aspect public class TestAspect { /** * @Pointcut("execution(* com.mango.service.*.*(..))") * execution 括號(hào)中的是一個(gè)表達(dá)式露戒,表面在com.mango.service 這個(gè)包下的所有類(lèi)所有方法所有返回值,所有參數(shù) * 申明切入點(diǎn) * execution 關(guān)鍵字 * * com.mango.service. *. * (..) ) * 所有的返回值 包名 所有類(lèi) 所有方法 所有的參數(shù) */ @Pointcut("execution(* com.mango.service.*.*(..))") public void pointcut(){} /** * @Before("pointcut()") 前置通知捶箱,在切入點(diǎn)之前 * @param joinPoint 可以通過(guò)他來(lái)獲取方法以及參數(shù) */ @Before("pointcut()") public void before(JoinPoint joinPoint){ Object [] args = joinPoint.getArgs(); for (Object arg : args) { System.out.println("參數(shù)為:"+arg); } } /** * @param joinPoint * @param returnValue * @AfterReturning(value = "pointcut()",returning = "returnValue") * returning 獲取返回值 */ @AfterReturning(value = "pointcut()",returning = "returnValue") public void returning(JoinPoint joinPoint,Object returnValue){ System.out.println("結(jié)果為:"+returnValue); } }
@Service
public class TestService {
public int sum(int a ,int b ){
int sum = a+b;
return sum;
}
}
@SpringBootTest
class SpringbootAopApplicationTests {
@Autowired
private TestService testService;
@Test
void contextLoads() {
testService.sum(1,2);
}
}
參數(shù)為:1
參數(shù)為:2
結(jié)果為:3
其他的After之類(lèi)的就不再舉例了智什,用法都是一樣的
這樣就是實(shí)現(xiàn)了AOP,是不是很簡(jiǎn)單丁屎,其實(shí)AOP的使用時(shí)很簡(jiǎn)單的荠锭,重要的是理解AOP的這種思想
AOP的運(yùn)用的技術(shù)
SpringAOP使用了兩種代理機(jī)制,一種是基于JDK的動(dòng)態(tài)代理悦屏,另一種是基于CGLib的動(dòng)態(tài)代理节沦,之所以需要兩種代理機(jī)制,很大程度上是因?yàn)镴DK本身只提供基于接口的代理础爬,不支持類(lèi)的代理甫贯。
切面植入的方法:
編譯期織
類(lèi)裝載期織入
動(dòng)態(tài)代理織入 在運(yùn)行期為目標(biāo)類(lèi)添加增強(qiáng)生成子類(lèi)的方式,Spring AOP采用動(dòng)態(tài)代理織入切面
AOP 有兩種主要的框架看蚜,SpringAOP和AspectJ
在一般情況下使用SpringAOP就可以解決我們的問(wèn)題叫搁,如果無(wú)法解決,Spring支持對(duì)AspectJ 的集成供炎,可以使用AspectJ解決