05-AOP practical application scenarios

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 these cross-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