@AspectJ的詳細用法
在Spring AOP中目前只有執行方法這一個連接點,Spring AOP支持的AspectJ切入點指示符如下:
一些常見的切入點的例子
execution(public * * (. .)) 任意公共方法被執行時,執行切入點函數。
execution( * set* (. .)) 任何以一個“set”開始的方法被執行時,執行切入點函數。
execution( * com.demo.service.AccountService.* (. .)) 當接口AccountService 中的任意方法被執行時,執行切入點函數。
execution( * com.demo.service.. (. .)) 當service 包中的任意方法被執行時,執行切入點函數。
within(com.demo.service.) 在service 包裏的任意連接點。
within(com.demo.service. .) 在service 包或子包的任意連接點。
this(com.demo.service.AccountService) 實現了AccountService 接口的代理對象的任意連接點。
target(com.demo.service.AccountService) 實現了AccountService 接口的目標對象的任意連接點。
args(java.io.Serializable) 任何一個只接受一個參數,且在運行時傳入參數實現了 Serializable 接口的連接點
增強的方式:
@Before:方法前執行
@AfterReturning:運行方法後執行
@AfterThrowing:Throw後執行
@After:無論方法以何種方式結束,都會執行(類似於finally)
@Around:環繞執行
添加 PointCut類
該pointcut用來攔截test包下的所有類中的所有方法。
package com.aop.test1; import org.aspectj.lang.annotation.Pointcut; public class PointCuts { @Pointcut(value = "within(com.aop.test1.*)") public void aopDemo() { } }
添加Aspect類
該類中的advice將會用到上面的pointcut,使用方法請看各個advice的value屬性。
package com.aop.test1; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component @Aspect public class Aspect1 { @Before(value = "test.PointCuts.aopDemo()") public void before(JoinPoint joinPoint) { System.out.println("[Aspect1] before advise"); } @Around(value = "test.PointCuts.aopDemo()") public void around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("[Aspect1] around advise 1"); pjp.proceed(); System.out.println("[Aspect1] around advise2"); } @AfterReturning(value = "test.PointCuts.aopDemo()") public void afterReturning(JoinPoint joinPoint) { System.out.println("[Aspect1] afterReturning advise"); } @AfterThrowing(value = "test.PointCuts.aopDemo()") public void afterThrowing(JoinPoint joinPoint) { System.out.println("[Aspect1] afterThrowing advise"); } @After(value = "test.PointCuts.aopDemo()") public void after(JoinPoint joinPoint) { System.out.println("[Aspect1] after advise"); } }
添加測試用Controller
添加一個用於測試的controller,這個controller中只有一個方法,但是它會根據參數值的不同,會作出不同的處理:一種是正常返回一個對象,一種是拋出異常(因爲我們要測試@AfterThrowing這個advice)
package com.aop.test1; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/aop") public class AopTestController { @ResponseStatus(HttpStatus.OK) @RequestMapping(value = "/test", method = RequestMethod.GET) public Result test(@RequestParam boolean throwException) { // case 1 if (throwException) { System.out.println("throw an exception"); throw new RuntimeException("mock a server exception"); } // case 2 System.out.println("test OK"); return new Result() { { this.setId(111); this.setName("mock a Result"); } }; } public static class Result { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } }
我們會看到輸出的結果是:
[Aspect1] around advise 1 [Aspect1] before advisetest OK [Aspect1] around advise2 [Aspect1] after advise [Aspect1] afterReturning advise
異常情況,我們會看到輸出的結果是:
[Aspect1] around advise 1 [Aspect1] before advise throw an exception [Aspect1] after advise [Aspect1] afterThrowing advise
正常情況:
異常情況:
@Component @Aspect public class CacheAspect { @Around("execution(public * *(..)) and @annotation(checkCache)") public Object get(ProceedingJoinPoint jp, CheckCache checkCache) throws Throwable { } @AfterReturning(pointcut = "@annotation(evictCache)", returning = "retval") public void remove(JoinPoint jp, EvictCache evictCache, Object retval) { } }