SpringBoot——AOP

1. What is AOP

AOP: The abbreviation of Aspect Oriented Programming, which means: aspect-oriented programming. The goal of aspect-oriented programming is to separate concerns. What is a focus? It's the focus, it's what you do. If you are a son-in-law with no goals in life, you reach out for clothes every day, open your mouth for meals, and only know one thing all day long: play (this is your focus, you only need to do this one thing)! But there is a problem. Before you play, you still need to get up, put on clothes, put on shoes, make the quilt, make breakfast, etc., but you don’t want to pay attention to these things, and you don’t need to pay attention to them. You just want to play, so what should you do?

right! All these things are handed over to the servants. You have a dedicated servant A who dresses you, servant B who puts your shoes on, servant C who makes you a quilt, servant D who cooks for you, then you eat, go play (that's what you do for the day), you finish your business, come back, and then a series of servants start doing this and that for you again, and the day is over!

This is AOP. The advantage of AOP is that you only need to do your business, and others will do it for you. Maybe one day, you want to run naked and don't want to wear clothes, then you just fire servant A! Maybe one day, you still want to bring some money before you go out, then you can hire a servant E to help you withdraw money! This is AOP. Each person performs his or her own duties and can be combined flexibly to achieve a configurable and pluggable program structure.

2. AOP processing in Spring Boot

2.1 AOP dependencies

To use AOP, you first need to introduce AOP dependencies.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.2 Realize AOP aspect

Using AOP in Spring Boot is very simple. If we want to print some logs in the project, after introducing the above dependencies, we create a new class LogAspectHandler to define aspects and processing methods. Just add an @Aspect annotation to the class. The @Aspect annotation is used to describe an aspect class, which needs to be marked when defining the aspect class. The @Component annotation lets the class be managed by Spring.

@Aspect
@Component
public class LogAspectHandler {
 
}

Here are a few commonly used annotations and their usage:

1.@Pointcut:定义一个切面,即上面所描述的关注的某件事入口。
2.@Before:在做某件事之前做的事。
3.@After:在做某件事之后做的事。
4.@AfterReturning:在做某件事之后,对其返回值做增强处理。
5.@AfterThrowing:在做某件事抛出异常时,处理。

2.2.1 @Pointcut annotation

@Pointcut annotation: It is used to define a cutting surface (pointcut), which is the entrance of something concerned above. The pointcut determines what the joinpoint focuses on, allowing us to control when the advice is executed.

@Aspect
@Component
public class LogAspectHandler {
 
    /**
     * 定义一个切面,拦截com.itcodai.course09.controller包和子包下的所有方法
     */
    @Pointcut("execution(* com.itcodai.course09.controller..*.*(..))")
    public void pointCut() {}
}

The @Pointcut annotation specifies an aspect and defines what needs to be intercepted. Here are two commonly used expressions: one uses execution() and the other uses annotation().

Take the execution(* com.itcodai.course09.controller..*.*(..))) expression as an example, the syntax is as follows:

execution() 为表达式主体
第一个 * 号的位置:表示返回值类型,* 表示所有类型
包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.itcodai.course09.controller 包、子包下所有类的方法
第二个 * 号的位置:表示类名,* 表示所有类
*(..) :这个星号表示方法名,* 表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数

The annotation() method is to define an aspect for a certain annotation. For example, if we make an aspect for a method with @GetMapping annotation, we can define the aspect as follows:

@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
public void annotationCut() {}

Then, if you use this aspect, you will cut into the annotation is @GetMapping method. Because in actual projects, there may be different logical processing for different annotations, such as @GetMapping, @PostMapping, @DeleteMapping, etc. Therefore, this method of cutting in according to annotations is also very commonly used in actual projects.

2.2.2 @Before annotation

The method specified by the @Before annotation is executed before the aspect cuts into the target method. You can do some log processing, and you can also do some information statistics, such as obtaining the user's request url and user's ip address, etc. This can be used when making a personal site, and it is a common method. For example:

@Aspect
@Component
public class LogAspectHandler {
 
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
    /**
     * 在上面定义的切面方法之前执行该方法
     * @param joinPoint jointPoint
     */
    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint) {
        logger.info("====doBefore方法进入了====");
 
        // 获取签名
        Signature signature = joinPoint.getSignature();
        // 获取切入的包名
        String declaringTypeName = signature.getDeclaringTypeName();
        // 获取即将执行的方法名
        String funcName = signature.getName();
        logger.info("即将执行方法为: {},属于{}包", funcName, declaringTypeName);
        
        // 也可以用来记录一些信息,比如获取请求的url和ip
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 获取请求url
        String url = request.getRequestURL().toString();
        // 获取请求ip
        String ip = request.getRemoteAddr();
        logger.info("用户请求的url为:{},ip地址为:{}", url, ip);
    }
}

The JointPoint object is very useful. It can be used to obtain a signature, and then the signature can be used to obtain the requested package name, method name, including parameters (obtained through joinPoint.getArgs()) and so on.

2.2.3 @After annotation

The @After annotation corresponds to the @Before annotation. The specified method is executed after the aspect cuts into the target method, and some log processing after completing a certain method can also be done.

@Aspect
@Component
public class LogAspectHandler {
 
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
    /**
     * 定义一个切面,拦截com.itcodai.course09.controller包下的所有方法
     */
    @Pointcut("execution(* com.itcodai.course09.controller..*.*(..))")
    public void pointCut() {}
 
    /**
     * 在上面定义的切面方法之后执行该方法
     * @param joinPoint jointPoint
     */
    @After("pointCut()")
    public void doAfter(JoinPoint joinPoint) {
 
        logger.info("====doAfter方法进入了====");
        Signature signature = joinPoint.getSignature();
        String method = signature.getName();
        logger.info("方法{}已经执行完", method);
    }
}

At this point, let's write a Controller to test the execution results, and create a new AopController as follows:

@RestController
@RequestMapping("/aop")
public class AopController {
 
    @GetMapping("/{name}")
    public String testAop(@PathVariable String name) {
        return "Hello " + name;
    }
}

Start the project, enter localhost:8080/aop/CSDN in the browser, and observe the output information of the console:

====doBefore方法进入了====  
即将执行方法为: testAop,属于com.itcodai.course09.controller.AopController包  
用户请求的url为:http://localhost:8080/aop/name,ip地址为:0:0:0:0:0:0:0:1  
====doAfter方法进入了====  
方法testAop已经执行完

From the printed log, you can see the logic and sequence of program execution, and you can intuitively grasp the actual functions of the two annotations @Before and @After.

2.2.4 @AfterReturning annotation

The @AfterReturning annotation is somewhat similar to @After, the difference is that the @AfterReturning annotation can be used to capture the return value after the cut-in method is executed, and enhance the business logic of the return value, for example:

@Aspect
@Component
public class LogAspectHandler {
 
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
    /**
     * 在上面定义的切面方法返回后执行该方法,可以捕获返回对象或者对返回对象进行增强
     * @param joinPoint joinPoint
     * @param result result
     */
    @AfterReturning(pointcut = "pointCut()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
 
        Signature signature = joinPoint.getSignature();
        String classMethod = signature.getName();
        logger.info("方法{}执行完毕,返回参数为:{}", classMethod, result);
        // 实际项目中可以根据业务做具体的返回值增强
        logger.info("对返回参数进行业务上的增强:{}", result + "增强版");
    }
}

It should be noted that in the @AfterReturning annotation, the value of the attribute returning must be consistent with the parameter, otherwise it will not be detected. The second input parameter in this method is the return value of the cut method. In the doAfterReturning method, the return value can be enhanced and encapsulated according to business needs. Let's restart the service and test it again (I won't post the redundant log):

方法testAop执行完毕,返回参数为:Hello CSDN  
对返回参数进行业务上的增强:Hello CSDN增强版

2.2.5 @AfterThrowing annotation

As the name implies, the @AfterThrowing annotation is when an exception is thrown when the cut method is executed, it will enter the @AfterThrowing annotated method for execution, and some exception handling logic can be done in this method. It should be noted that the value of the throwing attribute must be consistent with the parameter, otherwise an error will be reported. The second input parameter in this method is the thrown exception.

/**
 * 使用AOP处理log
 * @author shengwu ni
 * @date 2018/05/04 20:24
 */
@Aspect
@Component
public class LogAspectHandler {
 
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
    /**
     * 在上面定义的切面方法执行抛异常时,执行该方法
     * @param joinPoint jointPoint
     * @param ex ex
     */
    @AfterThrowing(pointcut = "pointCut()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        Signature signature = joinPoint.getSignature();
        String method = signature.getName();
        // 处理异常的逻辑
        logger.info("执行方法{}出错,异常为:{}", method, ex);
    }
}

I will not test this method, you can test it yourself.

3. Summary

This lesson explains in detail the aspect AOP in Spring Boot, mainly introduces the introduction of AOP in Spring Boot, the use of common annotations, the use of parameters, and the introduction of common APIs. AOP is very useful in actual projects. Before and after the implementation of the aspect method, corresponding preprocessing or enhancement processing can be done according to the specific business. At the same time, it can also be used for exception capture processing, and AOP can be used reasonably according to specific business scenarios.

Guess you like

Origin blog.csdn.net/qq_39367410/article/details/128864028