(Respect the fruits of labor, reproduced please indicate the source: juejin.cn/post/684490…)

This section summarizes and introduces AOP technologies in Spring.

Spring is a lightweight IOC and AOP container framework. Is a set of frameworks that provide foundational services for Java applications. It is intended to simplify enterprise application development by allowing developers to focus only on business requirements.

AOP:

Faceted programming refers to extending functionality without modifying the source code, separating functional code from business logic code.

Main functions:

Logging, performance statistics, security controls, transaction handling, exception handling, and more.

Main intention:

By separating logging, performance statistics, security controls, transaction handling, exception handling, etc., from the business logic code, we hope to separate these behaviors into methods that do not guide the business logic, and thus change these behaviors without affecting the business logic code.

Features of AOP:

Horizontal extraction mechanism is adopted to replace the traditional vertical inheritance system repetitive code.

AOP operational terms:

  • Joinpoint: Methods in a class that can be enhanced. These methods are called join points
  • Pointcut: Pointcuts are definitions of which JoinPoints we want to intercept
  • Advice: Advice means that all you need to do after intercepting Joinpoint is advise. Notifications are divided into pre-notification, post-notification, exception notification, final notification, and surround notification (function to be completed in section).
  • Aspect: Is a combination of a pointcut and an introduction
  • Introduction: Introduction is a special notification that dynamically adds methods or fields to a class at run time without modifying the class code.
  • Target: The Target object of the agent (the class to be enhanced)
  • Weaving is applying enhancements to goals and advice to targets
  • Proxy: When a class is woven into AOP for enhancement, a result Proxy class is produced

In fact, we only need this simple memory:

Pointcuts are methods that can be enhanced in a class. For example, in practice, only individual methods can be enhanced, and one of the methods that is actually enhanced can be defined as a pointcut.

Notification/enhancement refers to enhanced logic, such as extended logging, which is called enhancement.

Facet is the process of applying enhancements to specific methods called facets.

AOP implementation:

Spring’s AOP technology is implemented using dynamic proxies at the bottom. In SpringBoot, AOP technology is implemented with aspects, interceptors and filters. In this post, we will focus on common aspects and interceptor implementations.

In the Spring (I) : Beans scoping article we set up a simple SpringBoot project, which we continue to reuse for AOP demonstrations.

Aspect

In the SpringBoot project in the previous section, we started by adding the required dependencies for AOP:

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

Then create a section class as follows:

WebAcpect:

package com.ywq.interceptor;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/** * Created by Yanwenqiang on 2019-11-30 * Defines a section class */
@Aspect
@Component
public class WebAcpect {

    / * * * define the breakthrough point, the breakthrough point for the com. Ywq) controller. All the functions under TestController * /
    @Pointcut("execution(* com.ywq.controller.TestController.*(..) )")
    public void acpectMethod(a){}

    /** * pre-notification: notification performed before the join point *@param joinPoint
     * @throws Throwable
     */
    @Before("acpectMethod()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // The request is received, and the request content is recorded
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // Record the request
        System.out.println("URL:" + request.getRequestURL().toString());
        System.out.println("Method:" + request.getMethod());
        System.out.println("Class method:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        System.out.println("Parameter:"+ Arrays.toString(joinPoint.getArgs())); }}Copy the code

In the Aspect class, we need to annotate @aspect to indicate that this is a Aspect class, then annotate @Component to indicate that this is a Bean, and then we need to configure the pointcut. The configuration mode is as follows:

Pointcuts are configured using expressions, commonly used: Execution (< access modifier >? < return type >< method name >(< parameter >)< exception >)

  • execution(* com.ywq.controller.TestController.add(..) ) represents the add method in the current path
  • execution(* com.ywq.controller.TestController.*(..) ) : represents all methods in the current path
  • execution(* .(..) ) : represents all methods

For example, matching all methods that start with save can be configured as execution(* save*(..). )

In this case, we show only the pre-notification, and the rest of the notification is the same.

Then look at TestController:

package com.ywq.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/** * created by yangwenqiang on 2019-11-30 */
@RequestMapping("/test")
@RestController
public class TestController {

    @RequestMapping(value = "/scopeTest", method = RequestMethod.GET)
    public String testScope(HttpServletRequest request,
                            @RequestParam(value = "name") String name) {

        return "Hello, "+ name; }}Copy the code

Next, we start the SpringBoot service as follows:

http://localhost:8632/test/scopeTest?name=ywq

However, using aspects to implement AOP, especially to intercept interfaces to the Controller layer, seems a bit odd. In fact, in SpringBoot, we generally use Interceptor to achieve interface oriented programming, interception request, increase the corresponding functional modules.

The interceptor

SpringBoot the interceptors can be realized through HandlerInterceptorAdapter inherited abstract class or interface HandlerInterceptor will come true.

In abstract classes and interfaces, there are three methods:

  • PreHandle: Intercepts the request as soon as it comes in. Boolean returns true to continue execution; false to stop execution. Generally used for login verification.
  • PostHandle: Intercepts operations on modelAndView after a method successfully returns and before the view renders.
  • AfterCompletion: Intercepts the successful return of a method after the view has been rendered to log the successful return.

Let’s take a look at the HandlerInterceptor in the JDK:

Next, we first look at using the abstract class HandlerInterceptorAdapter interceptor to:

AuthInterceptor:

package com.ywq.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/ * * * created by yangwenqiang on the 2019-11-30 * * / interceptor HandlerInterceptorAdapter inherited abstract class
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // The interface executes this method before executing it. False indicates interception, true indicates permit
        String name = request.getParameter("name");
        System.out.println("Name in argument:" + name);

        return true; }}Copy the code

Then you also need a configuration class AuthConfig as follows:

package com.ywq.config;

import com.ywq.interceptor.AuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class AuthConfig implements WebMvcConfigurer {

    // Inject interceptor
    @Autowired
    private AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // Register interceptors
        registry.addInterceptor(authInterceptor).addPathPatterns("/test/scopeTest"); }}Copy the code

In this way, we can use HandlerInterceptorAdapter implements a blocker, start SpringBoot service, enter http://localhost:8632/test/scopeTest? in your browser If name=ywq, you can see the following result:

Next, let’s look at implementing an interceptor using the HandlerInterceptor interface:

CheckInterceptor:

package com.ywq.interceptor;

import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class CheckInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // The interface executes this method before executing it. False indicates interception, true indicates permit
        String name = request.getParameter("name");
        System.out.println("[CheckInterceptor] - Name in parameter:" + name);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}@Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}}Copy the code

The CheckConfig configuration class is as follows:

package com.ywq.config;

import com.ywq.interceptor.CheckInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/** ** ** created by Yangwenqiang on 2019-11-30 ** This is a config class */
 @Configuration
public class CheckConfig extends WebMvcConfigurationSupport {

    // Inject interceptor
    @Autowired
    private CheckInterceptor checkInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // Register interceptors
        registry.addInterceptor(checkInterceptor);
        super.addInterceptors(registry); }}Copy the code

Start SpringBoot service, enter http://localhost:8632/test/scopeTest? in your browser Name =yangwenqiang, the result can be seen as follows:

In general, we will first abstract class HandlerInterceptorAdapter to implement interceptors, because can be method coverage as needed. If AuthConfig and CheckConfig are troublesome, you can register the interceptor in the launcher class, as shown in the following example:

package com.ywq;

import com.ywq.interceptor.AuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/** * created by yangwenqiang on 2019-11-30 */

@SpringBootApplication
@ServletComponentScan
public class StartApplication implements WebMvcConfigurer {

    @Autowired
    private AuthInterceptor authInterceptor;

    // Start the SpringBoot service
    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class,args);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // Register interceptors
        registry.addInterceptor(authInterceptor).addPathPatterns("/test/scopeTest"); }}Copy the code


Conclusion:

In this section, we mainly explain the idea of AOP aspect oriented programming and its concrete implementation. To sum up, AOP implemented in the aspect-style is generally used to add corresponding additions to Service methods or business logic methods; The interceptor mainly intercepts the Controller interface of the Web layer.

See my GitHub for the complete project code covered in this section


In the following chapters, I will continue to update some of the tips I use in using Spring. I hope you can pay attention to ~


If it is helpful to you, remember to like ha, welcome everyone to pay attention to my blog, pay attention to the public number (Wenqiang’s technology cabin), learn more technical knowledge, travel with the ocean of knowledge ~