SpringAOP切入點規范及獲取方法參數的實現
切入點規范
@Pointcut("execution(* com.example.server.service.TeacherService.*(..))")
上面的切入點會切入com.example.server.service.TeacherService下面的所有方法。
下面來詳細介紹一下切入點表達式的規范。
1、execution():表達式主體。
2、第一個位置:表示返回類型, *號表示所有的類型。
3、第二個位置:表示需要攔截的包名.類名.方法名(方法參數)。
需要註意的是必須是全類名。其中可以使用*表示所有包。
比如說:com.example.server.service.表示service包下的所有類;com.example.server..則表示server包下的所有包及其所有類。
可以具體指定某一個方法,也可以用表示該類的所有方法(滿足之前的返回類型)
同樣,參數可以是具體的,例如:(int, String),也可以用(..)來表示任意參數。(隻有參數匹配的方法才能被切入)
AOP中獲取方法參數
"execution(* com.example.server.service.TeacherService.uploadExperience(..)) && args(userId)"
大傢可以看到,在以上表達式的基礎上添加瞭一點改動,這樣我們就能在AOP中獲取到切入方法調用時的參數,這樣我們就能在AOP方法中使用這個參數。
以下是一個示例:
@After("execution(* com.example.server.service.TeacherService.uploadExperience(..)) && args(userId)") public void updateLevel(Long userId){ //代碼塊,現在就可以在代碼塊中使用userId }
AOP獲取session的參數
有時需要在AOP中使用到之前存儲在session中的值。其實這也非常簡單。
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpSession session = attr.getRequest().getSession(true); long userId = (long) session.getAttribute(USER_ID);
同理,我們通過ServletRequestAttributes也可以獲取到request和response
HttpServletResponse response = attr.getResponse(); HttpServletRequest request = attr.getRequest();
SpringAOP:獲取切入點註釋的參數
spring aop如何在切面類中獲取切入點相關方法的參數、方法名、返回值、異常等信息
aop思想可以很好的幫助我們實現代碼的解耦,比如我們之前提到的,將日志代碼與業務層代碼完全獨立,通過spring aop的代理類進行整合。在切面類中,我們也能夠通過spring提供的接口,很好的獲取原切入點的相關信息。
首先,我們還是從代碼著手
業務層代碼StudentServiceImpl
@Service("studentService") public class StudentServiceImpl implements StudentService { @Override public int addStudent(Student student) throws Exception { System.out.println("addStudent...業務層代碼執行..."); return 1; } @Override public int deleteStudent(Integer id) throws Exception{ System.out.println("deleteStudent...業務層代碼執行..."); int i = 1/0; return 0; } }
切面類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+"方法執行前..."); System.out.println("參數為:"+ Arrays.asList(args)); } @After("execution(* com.wuwl.service.impl.StudentServiceImpl.*(..) )") public void doAfter(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println(methodName+"方法執行後..."); } @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()); } }
測試類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); } }
最後是日志輸出結果
addStudent方法執行前…
參數為:[com.wuwl.domain.Student@7e5c856f]
addStudent…業務層代碼執行…
addStudent方法執行後…
addStudent方法返回,返回值為:1
==================割===============
deleteStudent方法執行前…
參數為:[1]
deleteStudent…業務層代碼執行…
deleteStudent方法執行後…
deleteStudent方法異常,異常信息為:/ by zero
關於切入點方法的相關信息,spring很好的封裝在瞭org.aspectj.lang.JoinPoint接口中,這裡需要註意的是,在org.aopalliance.intercept包下,也有這樣命名的一個接口,千萬不要搞錯瞭。
joinPoint.getArgs()方法可以返回切入方法的參數信息,返回值為一個數組,遍歷即可獲取;joinPoint.getSignature()方法的返回值為方法簽名,簽名接口中就包括方法名之類的信息。
如果需要在通知方法中獲取切入方法的返回值,或者異常信息,則需要使用到對應註解的對應屬性才行。
點開@AfterReturning註解可以看到一個String returning() default “”;屬性,在通知方法中添加返回值參數,然後再註解中聲明該參數為切入方法的返回值即可,操作方法可參考上面的代碼。
同理可以,使用@AfterThrowing註解的String throwing() default “”;屬性,可以獲取到切入方法拋出的異常信息。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Springboot如何使用Aspectj實現AOP面向切面編程
- 使用Spring開啟註解AOP的支持放置的位置
- 基於SpringAop中JoinPoint對象的使用說明
- SpringBoot AOP @Pointcut切入點表達式排除某些類方式
- SpringAop日志找不到方法的處理