https://juejin.cn/post/6844903720203862023
https://blog.51cto.com/u_15155081/2720729
package com.yangxin.core.transaction;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class TransactionDemo2 {
@Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))")
public void point(){
}
@Before(value="point()")
public void before(){
System.out.println("transaction begin");
}
@AfterReturning(value = "point()")
public void after(){
System.out.println("transaction commit");
}
@Around("point()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("transaction begin");
joinPoint.proceed();
System.out.println("transaction commit");
}
}
切面(Aspect):是一個(gè)類殿衰,里面定義了通知與切點(diǎn)罐脊。
切點(diǎn)(PointCut):表達(dá)式瞎嬉。就是告訴程序要在執(zhí)行哪些核心業(yè)務(wù)的時(shí)候唐片,執(zhí)行非核心的業(yè)務(wù)。
通知(advice):五種通知方式:
@Before:前置通知柠掂,在調(diào)用目標(biāo)方法之前執(zhí)行通知定義的任務(wù)
@After:后置通知项滑,在目標(biāo)方法執(zhí)行結(jié)束后,無(wú)論執(zhí)行結(jié)果如何都執(zhí)行通知定義的任務(wù)
@After-returning:后置通知涯贞,在目標(biāo)方法執(zhí)行結(jié)束后枪狂,如果執(zhí)行成功,則執(zhí)行通知定義的任務(wù)
@After-throwing:異常通知肩狂,如果目標(biāo)方法執(zhí)行過(guò)程中拋出異常摘完,則執(zhí)行通知定義的任務(wù)
@Around:環(huán)繞通知,在目標(biāo)方法執(zhí)行前和執(zhí)行后傻谁,都需要執(zhí)行通知定義的任務(wù)。
連接點(diǎn)(Join point)
??連接點(diǎn)是在應(yīng)用執(zhí)行過(guò)程中能夠插入切面的一個(gè)點(diǎn)列粪。
<aop:aspectj-autoproxy/> 使用這個(gè)在springaop中開啟aspectJ注解
审磁、
1.通過(guò) @EnableAspectJAutoProxy解或者 XML 配置(
<aop:aspect-autoproxy>)可以激活 AOP 模塊谈飒,底層會(huì)注冊(cè)一個(gè) AbstractAutoProxyCreator 類型的 Bean 完成 AOP 自動(dòng)代理
2.Spring AOP 中的自動(dòng)代理主要由 AbstractAutoProxyCreator 這個(gè) Bean 進(jìn)行創(chuàng)建,因?yàn)樗鼘?shí)現(xiàn)了幾種 BeanPostProcessor态蒂,例如在 Bean 加載過(guò)程中杭措,初始化后會(huì)調(diào)用 AbstractAutoProxyCreator 的方法進(jìn)行處理,返回一個(gè)代理對(duì)象
這個(gè)地方存疑钾恢?:初始化的時(shí)候會(huì)引入其他的bean手素,解決bean的循環(huán)依賴的時(shí)候,三級(jí)緩存是可以生成代理對(duì)象瘩蚪,這個(gè)地方我覺得應(yīng)該是沒有循環(huán)依賴的在beanpostprocess.afterInitialization
之后實(shí)現(xiàn)泉懦,有依賴場(chǎng)景在初始化的時(shí)候進(jìn)行生成了
解決上面的疑問(wèn)
Spring AOP 自動(dòng)代理的實(shí)現(xiàn)主要由 AbstractAutoProxyCreator 完成,它實(shí)現(xiàn)了
BeanPostProcessor疹瘦、SmartInstantiationAwareBeanPostProcessor 和InstantiationAwareBeanPostProcessor
三個(gè)接口崩哩,那么這個(gè)類就是 Spring AOP 的入口,在這里將 Advice 織入我們的 Bean 中言沐,創(chuàng)建代理對(duì)象邓嘹。
三級(jí)緩存走的類依賴
總結(jié)創(chuàng)建代理對(duì)象
通過(guò)1.getAdvicesAndAdvisorsForBean(),找出合適的advisor對(duì)象
2.通過(guò)createProxy()险胰,根據(jù)找到的advisor創(chuàng)建一個(gè)代理對(duì)象汹押,jdk動(dòng)態(tài)代理或者CGlib動(dòng)態(tài)代理
(這個(gè)createProxy就是在warpIfNessary中的方法)
設(shè)計(jì)模式使用:
super: 代理模式
1.策略模式:
createAopProxy
2.模板模式
子類實(shí)現(xiàn)具體的方法,父類實(shí)現(xiàn)模板方法
3.責(zé)任鏈模式:
具體處理者接到請(qǐng)求后起便,可以選擇將請(qǐng)求處理掉鲸阻,或者將請(qǐng)求傳給下家。由于具體處理者持有對(duì)下家的引用
4.適配器:
將目標(biāo)類和適配者類解耦缨睡,通過(guò)引入一個(gè)適配器類來(lái)重用現(xiàn)有的適配者類鸟悴,而無(wú)須修改原有代碼。
實(shí)現(xiàn):
1.全部通過(guò)xml實(shí)現(xiàn):
切面實(shí)現(xiàn)(log日志)
package com.lagou.edu.utils;
/**
* @author 應(yīng)癲
*/
public class LogUtils {
/**
* 業(yè)務(wù)邏輯開始之前執(zhí)行
*/
public void beforeMethod(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
System.out.println(arg);
}
System.out.println("業(yè)務(wù)邏輯開始執(zhí)行之前執(zhí)行.......");
}
/**
* 業(yè)務(wù)邏輯結(jié)束時(shí)執(zhí)行(無(wú)論異常與否)
*/
public void afterMethod() {
System.out.println("業(yè)務(wù)邏輯結(jié)束時(shí)執(zhí)行奖年,無(wú)論異常與否都執(zhí)行.......");
}
/**
* 異常時(shí)時(shí)執(zhí)行
*/
public void exceptionMethod() {
System.out.println("異常時(shí)執(zhí)行.......");
}
/**
* 業(yè)務(wù)邏輯正常時(shí)執(zhí)行
*/
public void successMethod(Object retVal) {
System.out.println("業(yè)務(wù)邏輯正常時(shí)執(zhí)行.......");
}
}
public Object arroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("環(huán)繞通知中的beforemethod....");
Object result = null;
try{
// 控制原有業(yè)務(wù)邏輯是否執(zhí)行
// result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
}catch(Exception e) {
System.out.println("環(huán)繞通知中的exceptionmethod....");
}finally {
System.out.println("環(huán)繞通知中的after method....");
}
return result;
}
1.設(shè)置bean
2.設(shè)置aop:config
指定切點(diǎn)<AOP:POINT> 指定通知 <AOP:BEFORE/AFTER/AROUND>
<!--進(jìn)行aop相關(guān)的xml配置,配置aop的過(guò)程其實(shí)就是把a(bǔ)op相關(guān)術(shù)語(yǔ)落地-->
<!--橫切邏輯bean-->
<bean id="logUtils" class="com.lagou.edu.utils.LogUtils"></bean>
<!--使用config標(biāo)簽表明開始aop配置,在內(nèi)部配置切面aspect-->
<!--aspect = 切入點(diǎn)(鎖定方法) + 方位點(diǎn)(鎖定方法中的特殊時(shí)機(jī))+ 橫切邏輯 -->
<aop:config>
<aop:aspect id="logAspect" ref="logUtils">
<!--切入點(diǎn)鎖定我們感興趣的方法细诸,使用aspectj語(yǔ)法表達(dá)式-->
<!--..參數(shù)中的兩個(gè)點(diǎn)表示可以有參數(shù),也可以沒有參數(shù)陋守,有的話也可以是任意類型震贵,參數(shù)中的 *表示參數(shù)可以是任意類型,但必須有參數(shù)水评。 -->
<!--包名中的..兩個(gè)點(diǎn)表示中間可以是任意層-->
<!--<aop:pointcut id="pt1" expression="execution(* *..*.*(..))"/>-->
<aop:pointcut id="pt1" expression="execution(public void com.lagou.edu.service.impl.TransferServiceImpl.transfer(java.lang.String,java.lang.String,int))"/>
<!-- <aop:pointcut id="pt1" expression="execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))"/>
-->
<!--方位信息,pointcut-ref關(guān)聯(lián)切入點(diǎn)-->
<!--aop:before前置通知/增強(qiáng)-->
<aop:before method="beforeMethod" pointcut-ref="pt1"/>
<!--aop:after猩系,最終通知,無(wú)論如何都執(zhí)行-->
<!--aop:after-returnning中燥,正常執(zhí)行通知,retValue是接受方法的返回值的-->
<aop:after-returning method="successMethod" returning="retValue"/>
<!--aop:after-throwing寇甸,異常通知-->
<aop:around method="arroundMethod" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>-->
二:通過(guò)純注解方式實(shí)現(xiàn):
package com.lagou.edu.utils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @author 應(yīng)癲
*/
@Component
@Aspect
public class LogUtils {
@Pointcut("execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))")
public void pt1(){
}
/**
* 業(yè)務(wù)邏輯開始之前執(zhí)行
*/
@Before("pt1()")
public void beforeMethod(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
System.out.println(arg);
}
System.out.println("業(yè)務(wù)邏輯開始執(zhí)行之前執(zhí)行.......");
}
/**
* 業(yè)務(wù)邏輯結(jié)束時(shí)執(zhí)行(無(wú)論異常與否)
*/
@After("pt1()")
public void afterMethod() {
System.out.println("業(yè)務(wù)邏輯結(jié)束時(shí)執(zhí)行,無(wú)論異常與否都執(zhí)行.......");
}
/**
* 異常時(shí)時(shí)執(zhí)行
*/
@AfterThrowing("pt1()")
public void exceptionMethod() {
System.out.println("異常時(shí)執(zhí)行.......");
}
/**
* 業(yè)務(wù)邏輯正常時(shí)執(zhí)行
*/
@AfterReturning(value = "pt1()",returning = "retVal")
public void successMethod(Object retVal) {
System.out.println("業(yè)務(wù)邏輯正常時(shí)執(zhí)行.......");
}
/**
* 環(huán)繞通知
*
*/
/*@Around("pt1()")*/
public Object arroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("環(huán)繞通知中的beforemethod....");
Object result = null;
try{
// 控制原有業(yè)務(wù)邏輯是否執(zhí)行
// result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
}catch(Exception e) {
System.out.println("環(huán)繞通知中的exceptionmethod....");
}finally {
System.out.println("環(huán)繞通知中的after method....");
}
return result;
}
}
只需要在配置文件中增加一個(gè)配置項(xiàng)即可:
<!--開啟aop注解驅(qū)動(dòng)
proxy-target-class:true強(qiáng)制使用cglib
-->
<aop:aspectj-autoproxy/>
甚至我們可以不使用xml文件
使用純注解
在啟動(dòng)類上加上
@EnableAspectJAutoProxy