- Spring Boot進階:原理、實戰與面試題分析
- 鄭天民
- 1032字
- 2022-07-05 09:41:47
3.1.2 Spring AOP案例分析
在理解了AOP的相關概念以及Spring框架所提供的各種注解之后,在本節中,我們將通過代碼示例來展示注解的使用方法。
現在,假設有一個代表用戶賬戶的AccountService接口,如代碼清單3-1所示。
代碼清單3-1 AccountService接口代碼
public interface AccountService { boolean doAccountTransaction(Account source, Account dest, int amount) throws MinimumAmountException; }
可以看到,在該AccountService接口中定義了一個用于實現賬戶交易的doAccount-Transaction()方法。然后我們提供它的實現類,如代碼清單3-2所示。
代碼清單3-2 AccountService接口實現類代碼
public class AccountServiceImpl implements AccountService { private static final Logger LOGGER = Logger.getLogger(AccountServiceImpl.class); @Override public boolean doAccountTransaction(Account source, Account dest, int amount) throws MinimumAmountException { LOGGER.info("執行交易"); if (amount < 10) { throw new MinimumAmountException("交易金額過少"); } return true; } }
在doAccountTransaction()方法中,我們在執行交易之前記錄了操作日志,這種實現方式看上去沒有什么問題。如果針對交易操作,我們希望在該操作之前、之后、執行過程中以及拋出MinimumAmountException異常時都記錄對應的日志,那么實現起來就沒那么容易了。這個時候,可以通過AOP進行切入,并添加對應的日志記錄。基于Spring AOP,其實現過程如代碼清單3-3所示。
代碼清單3-3 AccountServiceAspect代碼
@Aspect public class AccountServiceAspect { private static final Logger LOGGER = Logger.getLogger(AccountServiceAspect.class); @Pointcut("execution(* com.springboot.aop.service.AccountService.doAccountTransaction(..))") public void doAccountTransaction() {} @Before("doAccountTransaction()") public void beforeTransaction(JoinPoint joinPoint) { LOGGER.info("交易前"); } @After("doAccountTransaction()") public void afterTransaction(JoinPoint joinPoint) { LOGGER.info("交易后"); } @AfterReturning(pointcut = "doAccountTransaction() and args(source, dest, amount)", returning = "isTransactionSuccessful") public void afterTransactionReturns(JoinPoint joinPoint, Account source, Account dest, Double amount, boolean isTransactionSuccessful) { if (isTransactionSuccessful) { LOGGER.info("轉賬成功 "); } } @AfterThrowing(pointcut = "doAccountTransaction()", throwing = "minimumAmountException") public void exceptionFromTransaction(JoinPoint joinPoint, MinimumAmountException minimumAmountException) { LOGGER.info("拋出異常: " + minimumAmountException.getMessage()); } @Around("doAccountTransaction()") public boolean aroundTransaction(ProceedingJoinPoint proceedingJoinPoint){ LOGGER.info("調用方法前 "); boolean isTransactionSuccessful = false; try { isTransactionSuccessful = (Boolean)proceedingJoinPoint.proceed(); } catch (Throwable e) { } LOGGER.info("調用方法后"); return isTransactionSuccessful; } }
上述AccountServiceAspect就是一個切面,代表了Spring AOP機制的典型使用方法,我們一一來展開討論。
首先,我們看到這里使用@Pointcut注解定義了一個切點,并通過execution()指示器限定該切點匹配的包結構為com.springboot.aop.service,匹配的方法是AccountService類的doAccountTransaction()方法。也就是說,針對com.springboot.aop.service.AccountService類中doAccountTransaction()方法的任何一次調用,都會觸發切面,也就會執行對應的通知邏輯。請注意,因為在Spring AOP中連接點只支持方法的調用,所以這里專門定義了一個doAccountTransaction()方法,并在該方法上使用了@Pointcut注解。
另外,在AccountServiceAspect中綜合使用了Spring AOP所提供的@Before、@After、@Around、@AfterThrowing和@AfterReturning注解來設置五種不同類型的通知。
- @Before:在方法調用之前調用通知。
- @After:在方法完成之后調用通知,無論方法執行成功與否。
- @Around:通知包裹了目標方法,在被通知的方法調用之前和調用之后執行自定義的行為。
- @AfterThrowing:在方法拋出異常后進行通知,可以通過該注解指定目標異常信息。
- @AfterReturning:在方法執行成功之后調用通知。
在使用這些通知注解時,同樣需要注意它們的目標切點都是添加了@Pointcut注解的doAccountTransaction()方法。這些注解對應的實現方法都不復雜,這里不一一展開討論。當執行AccountServiceImpl的doAccountTransaction()方法時,我們在控制臺中能夠看到如代碼清單3-4所示的日志信息,這說明Spring AOP已經生效。
代碼清單3-4 AOP輸出日志代碼示例
INFO AccountServiceAspect:50 - 調用方法前 INFO AccountServiceAspect:27 - 交易前 INFO AccountServiceImpl:14 - 執行交易 INFO AccountServiceAspect:32 - 交易后 INFO AccountServiceAspect:58 - 調用方法后
本案例的詳細實現代碼可以在以下地址下載:https://github.com/tianminzheng/spring-boot-examples/tree/main/SpringAopExample。
- GAE編程指南
- C語言程序設計(第3版)
- ReSharper Essentials
- Learning Linux Binary Analysis
- MATLAB 2020從入門到精通
- Instant Ext.NET Application Development
- 搞定J2EE:Struts+Spring+Hibernate整合詳解與典型案例
- Advanced UFT 12 for Test Engineers Cookbook
- 大學計算機基礎實驗指導
- Delphi開發典型模塊大全(修訂版)
- 寫給青少年的人工智能(Python版·微課視頻版)
- 數據結構:Python語言描述
- Effective C++:改善程序與設計的55個具體做法(第三版)中文版(雙色)
- Hands-On Data Visualization with Bokeh
- 區塊鏈社會:區塊鏈助力國家治理能力現代化