what is spring? How to realize the underlying principle of aop? How to apply?

Answer: Spring is a library. Its function is to provide a software framework. The purpose of this framework is to make the logic between businesses in the software clearer, the configuration more flexible, and the development easier. The means of implementation use AOP and IoC.

The underlying principle of aop is: the bottom layer is implemented by dynamic proxy technology and CGLIB (dynamic bytecode enhancement technology) provided by JDK. JDK dynamic proxy: JDK dynamic proxy is only for interface operations. CGLB proxy: can target java classes without interfaces and java classes with interfaces.

What is a proxy? You can refer to the following links: Analysis of the use and implementation principle of Java JDK dynamic proxy (AOP) - Programmer Sought 2. Java dynamic proxy class 3. How to use JDK's dynamic proxy? Fourth, how to achieve dynamic proxy? 5. Conclusion 1. What is an agency? Proxy is a common design pattern whose purpose is to provide a proxy for other objects to control access to an object. The proxy class is responsible for preprocessing messages for the delegate class, filtering and forwarding messages, and performing subsequent processing after the message is executed by the delegate class. Proxy mode UML diagram: simple structure diagram: in order to maintain behavior... https://blog.csdn.net/jiankunking/article/details/52143504

1. What is AOP?

Answer: AOP: Aspect-oriented programming, using AOP to isolate each part of the business logic, thereby reducing the coupling between the various parts of the business logic, improving the reusability of the program, and improving the efficiency of development.

It is mainly to dynamically add code through spring without changing the original code.

It's official, but I still don't understand it, right?

Simple explanation:

        The agent is easier to understand, it is nothing more than the meaning of processing on behalf of. For example, when you were in college, you always liked to skip classes. Therefore, you ask your classmate to help you answer it, while you play games in the dormitory... Your classmate just acts as an agent, taking the class instead of you.

        Yes, you read that right, proxies are that simple!

2.aop application scenarios

Using AOP can isolate our edge business and reduce the coupling of irrelevant business logic. Improve the reusability of the program and improve the efficiency of development. generally used for日志记录,性能统计,安全控制,权限管理,事务处理,异常处理,资源池管理。

3.为什么要使用aop?

The benefits of object-oriented programming (OOP) are obvious, and so are the disadvantages. When it is necessary to add a common method for multiple objects without inheritance relationship, such as logging, performance monitoring, etc., if the method of object-oriented programming is adopted, the same method needs to be added to each object, which results in It results in a large amount of repetitive work and a large amount of repetitive code, which is not conducive to maintenance. Aspect-Oriented Programming (AOP) is a supplement to Object-Oriented Programming. If the AOP method is used for log recording and processing, all log codes are concentrated in one place, and there is no need to add them in each method, which greatly reduces duplication of code.

4. Technical points

  1. Advice contains cross-cutting behavior that needs to be used for multiple application objects.

  2. Join Points are all points during program execution to which notifications can be applied.

  3. Pointcut (Poincut) is to define "where" to cut in, which join points will be notified. Obviously, the tangent point must be the join point.

  4. Aspect is a combination of advice and pointcut. Together, advice and pointcuts define what an aspect is all about—what, when, and where to perform functionality.

  5. Introduction allows us to add new methods or properties to an existing class.

  6. Weaving is the process of applying aspects to target objects and creating new proxy objects. It is divided into compile-time weaving, class-loading-time weaving, and run-time weaving.

5. Example application code

In this section, you will learn how to use the AOP aspect in Spring Boot 2.0 to uniformly process the request log and print the parameters related to the incoming and outgoing parameters.

First, look at the log output effect

As you can see, the start and end of each request are clear at a glance, and the following parameters are printed:

  • URL : request interface address;
  • HTTP Method : the method of the request, yes  POSTGET, or  DELETE etc.;
  • Class Method : corresponds to the full path of the Controller and which method to call;
  • IP : request IP address;
  • Request Args : Request input parameters, output in JSON format;
  • Response Args : Response output parameters, output in JSON format;
  • Time-Consuming : Request time-consuming;

The effect should be pretty good! Next, let's implement this function step by step. First, create a new Spring Boot Web project .

2. Add Maven dependencies

Add dependencies to the project  pom.xml file:

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

<!-- 用于日志切面中,以 json 格式打印出入参(本来使用阿里的 FASTJSON, 但是对于文件上传的接口,打印参数会报错,换为 Gson) -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
</dependency>

3. Configure AOP Aspects

Before configuring AOP aspects, we need to understand  aspectj the role of the following related annotations:

  • @Aspect : declare the class as an annotation class;
  • @Pointcut : Define a pointcut, followed by an expression, which can be defined as a method under a package, or a custom annotation, etc.;
  • After the pointcut is defined, it is time to make a fuss around this pointcut:
    • @Before : Weaving the relevant code before the pointcut;
    • @After : After the pointcut, weaving the relevant code;
    • @AfterReturning : After the pointcut returns the content, weave the relevant code, which is generally used in the scenario of processing the return value;
    • @AfterThrowing : used to handle the logic processing when the woven code throws an exception;
    • @Around : Weave code before and after the pointcut, and you can freely control when the pointcut is executed;

Next, define an  WebLogAspect.java aspect class with the following code:

package site.exception.springbootaopwebrequest.aspect;

import com.google.gson.Gson;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author www.exception.site (exception 教程网)
 * @date 2019/2/12
 * @time 14:03
 * @discription
 **/
@Aspect
@Component
public class WebLogAspect {

    private final static Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    /** 以 controller 包下定义的所有请求为切入点 */
    @Pointcut("execution(public * site.exception.springbootaopwebrequest.controller..*.*(..))")
    public void webLog() {}

    /**
     * 在切点之前织入
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 打印请求相关参数
        logger.info("========================================== Start ==========================================");
        // 打印请求 url
        logger.info("URL            : {}", request.getRequestURL().toString());
        // 打印 Http method
        logger.info("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        logger.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印请求的 IP
        logger.info("IP             : {}", request.getRemoteAddr());
        // 打印请求入参
        logger.info("Request Args   : {}", new Gson().toJson(joinPoint.getArgs()));
    }

    /**
     * 在切点之后织入
     * @throws Throwable
     */
    @After("webLog()")
    public void doAfter() throws Throwable {
        logger.info("=========================================== End ===========================================");
        // 每个请求之间空一行
        logger.info("");
    }

    /**
     * 环绕
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        // 打印出参
        logger.info("Response Args  : {}", new Gson().toJson(result));
        // 执行耗时
        logger.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
        return result;
    }

}

We  @Aspect declare it  WebLogAspect.java as an aspect class, and then  @Pointcut define the pointcut for printing the request log, which  site.exception.springbootaopwebrequest.controller is all the request interfaces under the package.

After the pointcut is defined, we  @Before print the relevant parameters of the request before the pointcut,  @Around print the time-consuming time of the request interface, and finally  @After finish the request.

At this point, the code related to the aspect is completed!

3. Test

We  test the effects of GETPOSTfile submission , and multiple file submission interfaces respectively. The interface definitions are as follows:

package site.exception.springbootaopwebrequest.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import site.exception.springbootaopwebrequest.entity.User;

/**
 * @author www.exception.site (exception 教程网)
 * @date 2019/2/16
 * @time 21:03
 * @discription
 **/
@RestController
public class TestController {

    private final static Logger logger = LoggerFactory.getLogger(TestController.class);

    /**
     * POST 方式接口测试
     * @param user
     * @return
     */
    @PostMapping("/user")
    public User testPost(@RequestBody User user) {
        logger.info("testPost ...");
        return user;
    }

    /**
     * GET 方式接口测试
     * @return
     */
    @GetMapping("/user")
    public String testGet(@RequestParam("username") String username,
                          @RequestParam("password") String password) {
        logger.info("testGet ...");
        return "success";
    }

    /**
     * 单文件上传接口测试
     * @return
     */
    @PostMapping("/file/upload")
    public String testFileUpload(@RequestParam("file") MultipartFile file) {
        logger.info("testFileUpload ...");
        return "success";
    }

    /**
     * 多文件上传接口测试
     * @return
     */
    @PostMapping("/multiFile/upload")
    public String testMultiFileUpload(@RequestParam("file") MultipartFile[] file) {
        logger.info("testMultiFileUpload ...");
        return "success";
    }
}

User.java:

package site.exception.springbootaopwebrequest.entity;

import java.io.Serializable;
import java.util.Date;

/**
 * @author www.exception.site (exception 教程网)
 * @date 2019/2/16
 * @time 21:00
 * @discription
 **/
public class User implements Serializable {
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 创建时间
     */
    private Date createTime;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}

3.1 GET interface test

Request  http://localhost:8080/user?username=张三&password=123456the interface and observe the log printing:

The GET  interface prints the log normally!

3.2 POST interface test

http://localhost:8080/user Request the POST  interface through Postman  :

Take a look at the console output:

The POST  interface is also OK!

3.3 Single file submission interface test

Request single file submission interface:  http://localhost:8080/file/upload :

The log output is as follows:

3.4 Multi-file submission interface test

Request single file submission interface:  http://localhost:8080/multiFile/upload :

Aspect log output:

Why not use FASTJSON

At the beginning, the author did use Ali's FASTJSON to print the input parameters, but for the file upload interface, the FASTJSON conversion would make an error, so I switched to Google's Gson.

Guess you like

Origin blog.csdn.net/qq_35207086/article/details/123178208