Spring AOP 指導教程
什么是Spring AOP
spring aop可以在spring構建的系統中使用面向切面編程。當然Spring Boot也是基于Spring構建的。使用AOP
可以實現諸如事務,日志以及安全校驗等通過切面統一完成的任務。他可以通過簡單的注解方式實現在方法執行前后來執行你自己的邏輯。
什么是advice, joinpoint和pointcut
- Joinpoint:程序的執行點,如方法的執行或者異常的處理。
- Pointcut:一個用來匹配joinpoint的斷言或者表達式。
- Advice:與一個pointcut關聯,并在匹配點運行。
advices的類型
- Before advice:在join point之前執行的advice,不能阻止程序的繼續運行。
- After returning advice:在join point完成之后執行的advice。
- After throwing advice:在執行的方法拋出異常之后執行。
- After advice:在執行的join point退出之后執行不論正常退出或者拋出了異常。
- Around advice:可以在方法調用之前或之后執行自定義行為,并且還可以選擇繼續執行join point或者執行另外的方法。

Spring AOP 示例
編寫Aspectclass然后寫相應的執行方法并在方法上寫joint-point表達式
面向切面編程首先需要在類上加@Aspect注解表名這是一個AOP管理的類,然后在方法上加上point-cut表達式用來匹配joint-point方法。
@Aspectpublic class EmployeeCRUDAspect { @Before("execution(* EmployeeManager.getEmployeeById(..))") //point-cut expression public void logBeforeV1(JoinPoint joinPoint) { System.out.println("EmployeeCRUDAspect.logBeforeV1() : " + joinPoint.getSignature().getName()); }}
寫由切面控制的方法(joint points)
首先將類注入到Spring中,之后寫正常的方法即可。
@Componentpublic class EmployeeManager{ public EmployeeDTO getEmployeeById(Integer employeeId) { System.out.println("Method getEmployeeById() called"); return new EmployeeDTO(); }}
在上面的例子中,logBeforeV1方法會在getEmployeeById方法執行之前執行。將會打印如下日志:
EmployeeCRUDAspect.logBeforeV1() : getEmployeeByIdMethod getEmployeeById() called
AOP注解
@Before
在切面控制的方法之前執行。
@Aspectpublic class LoggingAspect { @Before("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.*(..))") public void logBeforeAllMethods(JoinPoint joinPoint) { ... } @Before("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.getEmployeeById(..))") public void logBeforeGetEmployee(JoinPoint joinPoint) { ... }}
logBeforeAllMethods方法會在EmployeeManagerImpl中所有方法執行前執行。
@After
在切面控制的方法之后執行。
@Aspectpublic class LoggingAspect { @After("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.*(..))") public void logAfterAllMethods(JoinPoint joinPoint) { ... } @After("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.getEmployeeById(..))") public void logAfterGetEmployee(JoinPoint joinPoint) { ... }}
@Around
可以在方法執行前后切入。
@Aspectpublic class LoggingAspect { @Around("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.*(..))") public void logAroundAllMethods(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("****LoggingAspect.logAroundAllMethods() : " + joinPoint.getSignature().getName() + ": Before Method Execution"); try { joinPoint.proceed(); } finally { //Do Something useful, If you have } System.out.println("****LoggingAspect.logAroundAllMethods() : " + joinPoint.getSignature().getName() + ": After Method Execution"); }?}
@AfterReturning
在方法執行完成且沒有拋出任何異常的情況下。
@Aspectpublic class LoggingAspect { @AfterReturning("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.*(..))") public void logAfterReturningAllMethods() throws Throwable { System.out.println("****LoggingAspect.logAfterReturningAllMethods() "); }?}
以上示例中只用到了execution方式,還有一種使用@annotation可以對注解了指定接口的方法進行切面編程。這種用法在之前的mybatis多數據源中使用過。
另外還有很多AOP的注解,如果大家感興趣的話,會繼續把剩下的用法寫完~

