SpringAOP切入點(diǎn)規(guī)范及獲取方法參數(shù)的實(shí)現(xiàn)
切入點(diǎn)規(guī)范
@Pointcut("execution(* com.example.server.service.TeacherService.*(..))")
上面的切入點(diǎn)會(huì)切入com.example.server.service.TeacherService下面的所有方法。
下面來(lái)詳細(xì)介紹一下切入點(diǎn)表達(dá)式的規(guī)范。
1、execution():表達(dá)式主體。
2、第一個(gè)位置:表示返回類(lèi)型, *號(hào)表示所有的類(lèi)型。
3、第二個(gè)位置:表示需要攔截的包名.類(lèi)名.方法名(方法參數(shù))。
需要注意的是必須是全類(lèi)名。其中可以使用*表示所有包。
比如說(shuō):com.example.server.service.表示service包下的所有類(lèi);com.example.server..則表示server包下的所有包及其所有類(lèi)。
可以具體指定某一個(gè)方法,也可以用表示該類(lèi)的所有方法(滿足之前的返回類(lèi)型)
同樣,參數(shù)可以是具體的,例如:(int, String),也可以用(..)來(lái)表示任意參數(shù)。(只有參數(shù)匹配的方法才能被切入)
AOP中獲取方法參數(shù)
"execution(* com.example.server.service.TeacherService.uploadExperience(..)) && args(userId)"
大家可以看到,在以上表達(dá)式的基礎(chǔ)上添加了一點(diǎn)改動(dòng),這樣我們就能在AOP中獲取到切入方法調(diào)用時(shí)的參數(shù),這樣我們就能在AOP方法中使用這個(gè)參數(shù)。
以下是一個(gè)示例:
@After("execution(* com.example.server.service.TeacherService.uploadExperience(..)) && args(userId)") public void updateLevel(Long userId){ //代碼塊,現(xiàn)在就可以在代碼塊中使用userId }
AOP獲取session的參數(shù)
有時(shí)需要在AOP中使用到之前存儲(chǔ)在session中的值。其實(shí)這也非常簡(jiǎn)單。
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpSession session = attr.getRequest().getSession(true); long userId = (long) session.getAttribute(USER_ID);
同理,我們通過(guò)ServletRequestAttributes也可以獲取到request和response
HttpServletResponse response = attr.getResponse(); HttpServletRequest request = attr.getRequest();
SpringAOP:獲取切入點(diǎn)注釋的參數(shù)
spring aop如何在切面類(lèi)中獲取切入點(diǎn)相關(guān)方法的參數(shù)、方法名、返回值、異常等信息
aop思想可以很好的幫助我們實(shí)現(xiàn)代碼的解耦,比如我們之前提到的,將日志代碼與業(yè)務(wù)層代碼完全獨(dú)立,通過(guò)spring aop的代理類(lèi)進(jìn)行整合。在切面類(lèi)中,我們也能夠通過(guò)spring提供的接口,很好的獲取原切入點(diǎn)的相關(guān)信息。
首先,我們還是從代碼著手
業(yè)務(wù)層代碼StudentServiceImpl
@Service("studentService") public class StudentServiceImpl implements StudentService { @Override public int addStudent(Student student) throws Exception { System.out.println("addStudent...業(yè)務(wù)層代碼執(zhí)行..."); return 1; } @Override public int deleteStudent(Integer id) throws Exception{ System.out.println("deleteStudent...業(yè)務(wù)層代碼執(zhí)行..."); int i = 1/0; return 0; } }
切面類(lèi)StudentServiceLogger
@Aspect @Component public class StudentServiceLogger { @Before("execution(* com.wuwl.service.impl.StudentServiceImpl.*(..) )") public void doBefore(JoinPoint joinPoint){ Object[] args = joinPoint.getArgs(); String methodName = joinPoint.getSignature().getName(); System.out.println(methodName+"方法執(zhí)行前..."); System.out.println("參數(shù)為:"+ Arrays.asList(args)); } @After("execution(* com.wuwl.service.impl.StudentServiceImpl.*(..) )") public void doAfter(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println(methodName+"方法執(zhí)行后..."); } @AfterReturning(value = "execution(* com.wuwl.service.impl.StudentServiceImpl.*(..) )" , returning = "returning") public void doReturn(JoinPoint joinPoint,Object returning){ String methodName = joinPoint.getSignature().getName(); System.out.println(methodName+"方法返回,返回值為:"+returning); } @AfterThrowing(value = "execution(* com.wuwl.service.impl.StudentServiceImpl.*(..) )",throwing = "ex") public void doThrow(JoinPoint joinPoint,Exception ex){ String methodName = joinPoint.getSignature().getName(); System.out.println(methodName+"方法異常,異常信息為:"+ex.getMessage()); } }
測(cè)試類(lèi)AopTest
public class AopTest { ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); @Test public void test1() throws Exception { StudentService studentService = ac.getBean("studentService",StudentService.class); studentService.addStudent(new Student()); System.out.println("==================割==============="); studentService.deleteStudent(1); } }
最后是日志輸出結(jié)果
addStudent方法執(zhí)行前...
參數(shù)為:[com.wuwl.domain.Student@7e5c856f]
addStudent...業(yè)務(wù)層代碼執(zhí)行...
addStudent方法執(zhí)行后...
addStudent方法返回,返回值為:1
==================割===============
deleteStudent方法執(zhí)行前...
參數(shù)為:[1]
deleteStudent...業(yè)務(wù)層代碼執(zhí)行...
deleteStudent方法執(zhí)行后...
deleteStudent方法異常,異常信息為:/ by zero
關(guān)于切入點(diǎn)方法的相關(guān)信息,spring很好的封裝在了org.aspectj.lang.JoinPoint接口中,這里需要注意的是,在org.aopalliance.intercept包下,也有這樣命名的一個(gè)接口,千萬(wàn)不要搞錯(cuò)了。
joinPoint.getArgs()方法可以返回切入方法的參數(shù)信息,返回值為一個(gè)數(shù)組,遍歷即可獲??;joinPoint.getSignature()方法的返回值為方法簽名,簽名接口中就包括方法名之類(lèi)的信息。
如果需要在通知方法中獲取切入方法的返回值,或者異常信息,則需要使用到對(duì)應(yīng)注解的對(duì)應(yīng)屬性才行。
點(diǎn)開(kāi)@AfterReturning注解可以看到一個(gè)String returning() default "";屬性,在通知方法中添加返回值參數(shù),然后再注解中聲明該參數(shù)為切入方法的返回值即可,操作方法可參考上面的代碼。
同理可以,使用@AfterThrowing注解的String throwing() default "";屬性,可以獲取到切入方法拋出的異常信息。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java?-jar參數(shù)設(shè)置小結(jié)
本文主要介紹了Java?-jar參數(shù)設(shè)置小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06Spring Boot 數(shù)據(jù)校驗(yàn)@Valid+統(tǒng)一異常處理的實(shí)現(xiàn)
這篇文章主要介紹了Spring Boot 數(shù)據(jù)校驗(yàn)@Valid+統(tǒng)一異常處理的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-04-04springboot 在idea中實(shí)現(xiàn)熱部署的方法
這篇文章主要介紹了springboot 在idea中實(shí)現(xiàn)熱部署的方法,實(shí)現(xiàn)了熱部署,在每一次作了修改之后,都會(huì)自動(dòng)的重啟,非常節(jié)約時(shí)間,感興趣的小伙伴們可以參考一下2018-10-10java serialVersionUID解決序列化類(lèi)版本不一致問(wèn)題面試精講
這篇文章主要為大家介紹了serialVersionUID解決序列化類(lèi)版本不一致問(wèn)題的面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10Java基礎(chǔ)之選擇結(jié)構(gòu)與循環(huán)結(jié)構(gòu)
這篇文章主要介紹了Java基礎(chǔ)之選擇結(jié)構(gòu)與循環(huán)結(jié)構(gòu),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04詳解Java的JDBC API的存儲(chǔ)過(guò)程與SQL轉(zhuǎn)義語(yǔ)法的使用
這篇文章主要介紹了詳解Java的JDBC API的存儲(chǔ)過(guò)程與SQL轉(zhuǎn)義語(yǔ)法的使用,JDBC是Java用于連接使用各種數(shù)據(jù)庫(kù)的API,需要的朋友可以參考下2015-12-12Springboot集成fastDFS配置過(guò)程解析
這篇文章主要介紹了Springboot集成fastDFS配置過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11java僅用30行代碼就實(shí)現(xiàn)了視頻轉(zhuǎn)音頻的批量轉(zhuǎn)換
這篇文章主要介紹了java僅用30行代碼就實(shí)現(xiàn)了視頻轉(zhuǎn)音頻的批量轉(zhuǎn)換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04zookeeper實(shí)戰(zhàn)之實(shí)現(xiàn)分布式鎖的方法
Zookeeper實(shí)現(xiàn)分布式鎖比Redis簡(jiǎn)單,Zookeeper有一個(gè)特性,多個(gè)線程在Zookeeper里創(chuàng)建同一個(gè)節(jié)點(diǎn)時(shí),只有一個(gè)線程執(zhí)行成功,Zookeeper主要是利用臨時(shí)有序節(jié)點(diǎn)這一特性實(shí)現(xiàn)分布式鎖,感興趣的朋友跟隨小編一起學(xué)習(xí)吧2022-11-11java訪問(wèn)者模式的靜態(tài)動(dòng)態(tài)及偽動(dòng)態(tài)分派徹底理解
這篇文章主要為大家介紹了java訪問(wèn)者模式的靜態(tài)動(dòng)態(tài)及偽動(dòng)態(tài)分派徹底理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06