AOP practical cases
Transaction Control
In a business process, multiple DML statements may need to be completed together, so in order to ensure data security, it is necessary to add transaction control code to ensure that multiple DML statements succeed or fail at the same time
- The code format for controlling transactions for each business method in the business class is basically fixed. We can use
AOP ideas
to extract thesecross-business codes
so that the code can be duplicated. Easy to use and maintain
class business class 1{<!-- --> public void business method 1(){<!-- --> try{<!-- --> //Start transaction startTransaction(); //Execute core business logic step1(); step2(); step3(); .... // Submit transaction commitTransaction(); }catch(Exception e){<!-- --> //Rollback transaction rollbackTransaction(); } } public void business method 2(){<!-- --> try{<!-- --> //Start transaction startTransaction(); //Execute core business logic step1(); step2(); step3(); .... // Submit transaction commitTransaction(); }catch(Exception e){<!-- --> //Rollback transaction rollbackTransaction(); } } } class business class 2{<!-- --> public void business method 1(){<!-- --> try{<!-- --> //Start transaction startTransaction(); //Execute core business logic step1(); step2(); step3(); .... // Submit transaction commitTransaction(); }catch(Exception e){<!-- --> //Rollback transaction rollbackTransaction(); } } } //......
Step 1: Define two business classes (target classes) AccountService and OrderService
and business methods (target methods)
//Order-related business classes @Service public class OrderService {<!-- --> // Generate order method public void generate(){<!-- --> System.out.println("Generating orders"); } // Cancel order method public void cancel(){<!-- --> System.out.println("Canceling order"); } } // Business classes related to bank transfers @Service public class AccountService {<!-- --> //Transfer business method public void transfer(){<!-- --> System.out.println("Bank account transfer in progress"); } // Withdrawal business method public void withdraw(){<!-- --> System.out.println("Withdrawal operation in progress"); } }
Step 2: Define a transaction-related aspect class TransactionAspect
, write the code to control the transaction into the surround notification
method, and express it according to the pointcut
Insert the notification into the business method of the specified business class
@Component @Aspect public class TransactionAspect {<!-- --> // Transaction aspect class @Around("execution(* com.powernode.spring6.service..*(..))")// Around notification public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){<!-- --> //Code to control transactions try {<!-- --> // wraparound before System.out.println("Open transaction"); //Execute the target method of the target object proceedingJoinPoint.proceed(); // back wrap System.out.println("Commit transaction"); } catch (Throwable e) {<!-- --> System.out.println("Rollback transaction"); } } }
Step 3: Enable component scanning and automatic proxy
in the spring configuration file
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--Enable component scanning--> <context:component-scan base-package="com.powernode.spring6.service"/> <!--When automatic proxy is turned on, the spring container will check whether there is an @Aspect annotation on the class when scanning the class. If so, it will generate a proxy object for the aspect class --> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
Step 4: Execute the business method of the business class and check the execution status of the transaction control code in surround notification
public class AOPTest2 {<!-- --> @Test public void testTransaction(){<!-- --> ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Configuration.class); OrderService orderService = applicationContext.getBean("orderService", OrderService.class); AccountService accountService = applicationContext.getBean("accountService", AccountService.class); // Execute orderService method to generate orders orderService.generate(); //Execute orderService method to cancel the order orderService.cancel(); // Method to execute accountService transfer accountService.transfer(); // Method to execute accountService withdrawal accountService.withdraw(); } }
Open transaction Generating order commit transaction Open transaction Canceling order commit transaction Open transaction Bank account transfer in progress commit transaction Open transaction Withdrawal operation in progress commit transaction
Security Log
Requirement: Because additions, deletions, and modifications are dangerous behaviors, we need to record all users who perform additions, deletions, and modifications in the system after the project goes online
Step 1: Define business classes (target classes) UserService
and ProductService
and their business methods (target methods)
//User business class @Service public class UserService {<!-- --> public void getUser(){<!-- --> System.out.println("Get user information"); } public void saveUser(){<!-- --> System.out.println("Save user"); } public void deleteUser(){<!-- --> System.out.println("Delete user"); } public void modifyUser(){<!-- --> System.out.println("Modify user"); } } //Merchant business class @Service public class ProductService {<!-- --> public void getProduct(){<!-- --> System.out.println("Get product information"); } public void saveProduct(){<!-- --> System.out.println("Save product"); } public void deleteProduct(){<!-- --> System.out.println("Delete product"); } public void modifyProduct(){<!-- --> System.out.println("Modify product"); } }
Step 2: Define an aspect class SecurityAspect
responsible for security, write the code for recording security logs into the Notification
method, and express it according to the pointcut
Insert the notification into the business method of the specified business class
@Component @Aspect public class SecurityAspect {<!-- --> //Extract reusable pointcut expressions @Pointcut("execution(* com.powernode.spring6.biz..save*(..))") public void savePointcut(){<!-- -->} @Pointcut("execution(* com.powernode.spring6.biz..delete*(..))") public void deletePointcut(){<!-- -->} @Pointcut("execution(* com.powernode.spring6.biz..modify*(..))") public void modifyPointcut(){<!-- -->} // Use the extracted pointcut expression to specify that the notification only applies to methods of addition, deletion and modification. @Before("savePointcut() || deletePointcut() || modifyPointcut()") public void beforeAdivce(JoinPoint joinpoint){<!-- --> System.out.println("XXX operator is operating" + joinpoint.getSignature().getName() + "Method"); } }
Step 3: Enable component scanning and automatic proxy
in the spring configuration file
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--Enable component scanning, biz is also the business layer--> <context:component-scan base-package="com.powernode.spring6.biz"/> <!--When automatic proxy is turned on, the spring container will check whether there is an @Aspect annotation on the class when scanning the class. If so, it will generate a proxy object for the aspect class --> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
Step 4: Execute the business method of the business class and check the execution status of the code that records the security log in pre-notification
@Test public void testSecurity(){<!-- --> ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Configuration.class); UserService userService = applicationContext.getBean("userService", UserService.class); ProductService productService = applicationContext.getBean("productService", ProductService.class); // Call the add, delete, modify, check method of the userService object userService.getUser(); userService.saveUser(); userService.deleteUser(); userService.modifyUser(); //Call the add, delete, modify, check method of the productService object productService.getProduct(); productService.saveProduct(); productService.deleteProduct(); productService.modifyProduct(); }
Get user information XXX operator is operating the saveUser method save user XXX operator is operating the deleteUser method delete users XXX operator is operating the modifyUser method Modify user Get product information XXX operator is operating the saveProduct method Save product XXX operator is operating the deLeteProduct method Delete product XXX operator is operating the modifyProduct method Modify product