用文本文檔做網(wǎng)站今日頭條搜索引擎
文章目錄
- AOP的概念
- AOP術(shù)語
- AOP的實現(xiàn)
- AspectJ
- Spring AOP
- Spring AOP原理
- JDK動態(tài)代理
- CGLib動態(tài)代理
- SpringAOP代碼編寫規(guī)則
- 自定義切面
- 自定義切點
- 自定義通知
- 在通知中獲取當(dāng)前請求
- 代碼實例
- 一些選擇題
AOP的概念
? Aspect Oriented Programing,即面向方面(切面)編程。
? AOP是一種編程思想,是對OOP(面向?qū)ο缶幊?#xff09;的補充,可以進(jìn)一步提高編程的效率。
AOP術(shù)語
連接點表示的并不是一個點,而是一段代碼或一整個方法等
AOP的實現(xiàn)
AspectJ
- AspectJ是語言級的實現(xiàn)(一種新的語言),它擴展了Java語言,定義了AOP語法。
- AspectJ在編譯期織入代碼,它有一個專門的編譯器,用來生成遵守Java字節(jié)碼規(guī)范的class文件。
Spring AOP
- Spring AOP使用純Java實現(xiàn),它不需要專門的編譯過程,也不需要特殊的類裝載器。
- Spring AOP在運行時通過代理的方式織入代碼,只支持方法類型的連接點。
- Spring支持對AspectJ的集成。(遇到解決不了得問題,再用AspectJ)
Spring AOP原理
代理:給某個對象生成一個新的對象來代替它,調(diào)用時僅調(diào)用代理對象,而不調(diào)用原始對象
Spring中的bean都是通過容器去調(diào)用的,當(dāng)容器調(diào)用時發(fā)現(xiàn)目標(biāo)對象上有AOP的作用,就會去找代理對象,調(diào)用代理對象,而代理對象上有織入的代碼,能解決問題。
JDK動態(tài)代理
目標(biāo)對象必須要有接口(要求),才能被代理。代理時,自動生成接口的實現(xiàn)類,代替原實現(xiàn)類
- Java提供的動態(tài)代理技術(shù),可以在運行時創(chuàng)建接口的代理實例。
- Spring AOP默認(rèn)采用此種方式,在接口的代理實例中織入代碼。
CGLib動態(tài)代理
創(chuàng)建目標(biāo)對象的子類,用子類代替原來的對象(java支持多態(tài),故可用子類型來代替父類型)
- 采用底層的字節(jié)碼技術(shù),在運行時創(chuàng)建子類代理實例。
- 當(dāng)目標(biāo)對象不存在接口時,Spring AOP會采用此種方式,在子類實例中織入代碼。
SpringAOP代碼編寫規(guī)則
自定義切面
@Aspect:聲明當(dāng)前類是一個切面組件
@Component // 將切面組件聲明為bean令容器管理它
@Aspect
public class AlphaAspect { ... ... }
自定義切點
@Pointcut:自定義切點,聲明當(dāng)前方法是切點。
自定義一個空方法,加上 @Pointcut 注解,在注解中聲明要將切面織入到哪些bean哪些方法中,即使用哪些連接點
* 符號表示任意,在不同位置代表不同的數(shù)據(jù)
* 在開頭方法返回值位置上,代表任意類型的返回值
com.nowcoder.community.service.*.*(…) : service包下的 任意類中 的 任意方法,(…) 表示方法的所有參數(shù)
execution(* com.nowcoder.community.service..(…)): 表示service包下所有 業(yè)務(wù)組件(即類)的所有方法(不限參數(shù)和返回值)都要處理,都要匹配
@Pointcut("execution(* com.nowcoder.community.service.*.*(..))")public void pointcut() {}
自定義通知
自定義方法上加不同注解 表示在連接點不同位置織入當(dāng)前代碼,注解中需指定 針對哪些連接點植入該方法,即適用的鏈接點范圍
@Before:連接點前植入代碼
@After:連接點后植入代碼
@AfterReturning:拋異常時植入代碼
@Around:連接點前后都植入代碼
@After("pointcut()")public void after() {System.out.println("after");}
自定義的方法可以帶上一個參數(shù),代表連接點對象。通過連接點對象可以獲取鏈接點的信息,如連接點在哪個類中,是哪個方法?;蛘{(diào)用連接點中的代碼執(zhí)行
-
@Around標(biāo)識的方法中加 ProceedingJoinPoint
@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("around before");// proceed() 調(diào)用目標(biāo)組件的方法,用Object接收目標(biāo)組件方法的返回值Object obj = joinPoint.proceed();System.out.println("around after");return obj;}
-
其他注解 標(biāo)識的方法中加 JoinPoint
@Before("pointcut()")public void before(JoinPoint joinPoint) {// 得到織入目標(biāo)類名String className = joinPoint.getSignature().getDeclaringTypeName();// 得到織入目標(biāo)方法名String functionName = joinPoint.getSignature().getName();System.out.println(className+"."+functionName);}
在通知中獲取當(dāng)前請求
目的:當(dāng)前請求對象中包含很多信息,如用戶ip地址,請求內(nèi)容等,通過請求對象我們可以獲取這些信息
用于通知的方法不可以隨意添加Request對象作為參數(shù)
獲取Request對象:
-
利用 Request的工具類RequestContextHolder,通過getRequestAttributes()方法可以獲得RequestAttributes類型對象
-
ServletRequestAttributes 是 RequestAttributes 的子類,擁有更多的方法,故通常將返回類型強轉(zhuǎn)為子類型
-
通過ServletRequestAttributes可以獲得Request對象
@Before("pointcut()")public void before() {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();}
代碼實例
@Component // 將切面組件聲明為bean令容器管理它
@Aspect // 表示這是一個切面組件
public class AlphaAspect {// SpringAOP僅支持方法類型連接點@Pointcut("execution(* com.nowcoder.community.service.*.*(..))")public void pointcut() {}// 連接點前植入代碼@Before("pointcut()")public void before() {// 打印ip:用戶ip地址要從request中獲取ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();String ip = request.getRemoteHost();System.out.println(ip);}// 連接點后植入代碼@After("pointcut()")public void after() {System.out.println("after");}// 連接點有返回值以后植入代碼@AfterReturning("pointcut()")public void afterRetuning() {System.out.println("afterRetuning");}// 拋異常時植入代碼@AfterThrowing("pointcut()")public void afterThrowing() {System.out.println("afterThrowing");}// 連接點前后都植入代碼@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("around before");// proceed() 調(diào)用目標(biāo)組件的方法,用Object接收目標(biāo)組件方法的返回值Object obj = joinPoint.proceed();System.out.println("around after");return obj;}}
一些選擇題
B
A
D
D
圖片轉(zhuǎn)存中…(img-sP6qo5m5-1709223538149)]
B
[外鏈圖片轉(zhuǎn)存中…(img-zaELyrk5-1709223538150)]
A
[外鏈圖片轉(zhuǎn)存中…(img-44XalgTf-1709223538150)]
D
[外鏈圖片轉(zhuǎn)存中…(img-7ey2TUah-1709223538150)]
D
[外鏈圖片轉(zhuǎn)存中…(img-yevsttjk-1709223538151)]
A