preface
I have always wanted to understand the use of AOP, and most of the articles on the web are about the principle of using JDK proxy or Cglib proxy. For starters, I’d like to know more about how AOP is used, so I’ve compiled this article as a personal note, not describing the principles, but just how AOP is used in projects.
concept
- First of all, you need to know the concept of AOP, involving more concepts, if you need to understand clearly, you can refer to this article, very detailed, but also very vivid metaphor. Spring — AOP in Detail (AOP at a Glance)
I’ll just mention a few important concepts:
- Aspect: In code, this is the Aspect class, such as defining a logging Aspect class called LoggerAspect, which is the Aspect
- Pointcut: The scope of the rule, such as whether the method of your aspect class should apply to all classes in the package or only to the methods of one class in the package.
- Advice (enhanced) : For example, if you define A method in the aspect class LoggerAspect, and you specify that the scope of the pointcut is only applicable to A method of A class in A package, do you call the method of the aspect class before method A is executed or after method A is executed? Or do it both ways. This corresponds to the three actions in Advice, before, after and around, which are most commonly used.
- The way I understand AOP is to extract scattered reusable common logic and put it together as an aspect class whose methods can be customized when they are executed, sort of like an interceptor.
scenario
- I have a UserController class that has a method for adding users
@apiOperation (" Add user ")
@PostMapping("/addUser")
public ResultVo addUser(@Validated @RequestBody AddUserForm userForm){
if(userService.addUser(userForm)){
return ResultVoUtil.success();
}else{
returnResultVoUtil.error(ResultEnum.ADD_ERROR); }}Copy the code
- I want to print logs both before and after this method call, so I define a log aspect class LoggerAspect that defines two methods, The tangent point of the two method is UserController class method addUser (” execution (* com. HXH. Basic. Project. The controller. The UserController. AddUser (..) The Advice action is @before Before and @after
@Aspect
@Component
public class LoggerAspect {
// The main types of Advice are before,after,around; Around is the most commonly used advice, meaning to execute before and after code
// Before and after are used together
/** * addUser() is executed before */
@Before("execution(* com.hxh.basic.project.controller.UserController.addUser(..) )"
public void callBefore(a) {
System.out.println("before call method");
System.out.println("begin........................");
}
/** * addUser() is executed after */
@After("execution(* com.hxh.basic.project.controller.UserController.addUser(..) )"
public void callAfter(a) {
System.out.println("after call method");
System.out.println("end.............................."); }}Copy the code
- Advice can be used Around instead of @Before and @After
@Aspect
@Component
public class LoggerAspect {
// The main types of Advice are before,after,around; Around is the most commonly used advice, meaning to execute before and after code
// Before and after are used together
/ / = = = = = = = = = = = = used Around instead of Before and After the = = = = = = = = = = = = = = = = = = = = = = =
/** * Record the execution time *@paramPoint tangent point *@return
* @throws Throwable
*/
@Around("execution(* com.hxh.basic.project.controller.UserController.addUser(..) )"
public Object getMethodExecuteTime(ProceedingJoinPoint point) throws Throwable {
System.out.println("---------------getMethodExecuteTime------------------");
long startTime = System.currentTimeMillis();
// This code calls the target method, such as the addUser method of UserController
Object result = point.proceed();
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
System.out.println("executeTime=" + executeTime + "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
returnresult; }}Copy the code
- This is a simple use of AOP, but it’s not really flexible enough. If you want to record the execution times of multiple methods in UserController, you have to modify the pointcut rules to specify which methods to use. So in enterprise engineering, AOP is mostly used using annotations for custom control.
Annotation based AOP
- Start with a custom annotation
This way, if you want to use AOP on any method in the future, you can simply annotate that method
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OpLog {
/** * method description, you can use placeholders to get arguments :{{tel}} */
String value(a) default "";
/** * Log level: set your own, which is divided into 1-9 */
int level(a) default 4;
/ * * * operation type (enum) : mainly is the select, insert, update, delete * /
OperationType operationType(a) default OperationType.UNKNOWN;
/** * The object being operated on (enum here): can be any object, such as the table name (user), or the tool (redis) */
String operationUnit(a) default "unknown";
}
Copy the code
Add a method to LoggerAspect like this:
/ * * *@param point
* @return
* @throws Throwable
*/
// @Around("operationLog()")
@Around("@annotation(com.hxh.basic.project.aop.annotation.OpLog)")
public Object getMethodExecuteTimeForLogger(ProceedingJoinPoint point) throws Throwable {
System.out.println("---------------getMethodExecuteTime------------------");
long startTime = System.currentTimeMillis();
Object result = point.proceed();
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
System.out.println("executeTime=" + executeTime + "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
return result;
}
Copy the code
Put @oplog on any method that needs to record execution time:
/** * Add user *@paramUserForm form data *@returnSuccess or failure * using annotation-based AOP OpLog */
@JwtIgnore
@apiOperation (" Add user ")
@PostMapping("/addUser")
@oplog (value = "Add user ", level = 8, operationUnit = "UserController", operationType = operationType.insert)*
public ResultVo addUser(@Validated @RequestBody AddUserForm userForm){
if(userService.addUser(userForm)){
return ResultVoUtil.success();
}else{
returnResultVoUtil.error(ResultEnum.ADD_ERROR); }}Copy the code
-
This is the annotation-based APPROACH to AOP. If you want to invoke AOP in any method, you simply add annotations
-
See the blog link: Using AOP based on annotations in Spring