Details how to handle custom annotations using AOP of Spring Boot

  • 2020-12-19 21:05:31
  • OfStack

The Java annotations in the previous article explained the basic usage of Java annotations and implemented a simple testing tool with custom annotations. This article will show you how to use Spring Boot's AOP to simplify handling custom annotations and illustrate this by implementing a simple method called execution time statistics tool as an example.

AOP concept

Aspect-oriented programming (ES11en-ES12en programming) is a term in computer science that refers to a programming paradigm. The paradigm is based on a language construct called aspect (aspect), which is a new modularity mechanism for describing crosscutting concerns (crosscutting concern) that are scattered among objects, classes, or functions.

The sideway concept is derived from, but not limited to, improvements in object-oriented programming and can be used to improve traditional functions. Other side-related programming concepts include meta-object protocols, topics (subject), mixing (mixin), and delegates.

Note: Above defined by Chinese wikipedia (if can't access, the system can be changed by hosts file access, 198.35.26.96 zh. wikipedia. org # Chinese wikipedia, can help to this, if still not, then how to modify the system under the Internet for the trouble hosts file, under different system hosts file location is not 1 sample, if it is Linux or Mac system, I will tell you, like 1 file path is/etc/hosts), The translation of AOP is a bit different from the mainstream in China, where the translation of AOP is called "aspect-oriented programming". Don't get stuck in calling it "AOP", just know that it refers to the same thing.

If you want to know more about it, you can see how the big guys are pulling it apart. What is aspect-oriented programming, AOP? . So I'm just going to do the example right here.

Spring Boot AOP environment preparation

The corresponding dependency module is introduced in ES46en.ES47en


<!-- Spring Boot Depend on the package  -->
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.5.1.RELEASE</version>
</parent>
<dependencies>
  <!-- AOP Rely on the module  -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
  </dependency>
  <!-- Web Rely on the module  -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
</dependencies>

First implement a simple Web request processing

A simple Controller to handle Web requests.


package com.craneyuan.controller;

import com.craneyuan.service.IHelloWorldService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {
  @Autowired
  private IHelloWorldService helloWorldService;

  @RequestMapping(value = "/hello", method = RequestMethod.GET)
  public String hello(String name) {
    return helloWorldService.getHelloMessage(name);
  }
}

A simple HelloWorld service implementation class. I won't show you the definition of the interface.


package com.craneyuan.service.impl;

import com.craneyuan.annotation.AnalysisActuator;
import com.craneyuan.service.IHelloWorldService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class HelloWorldServiceImpl implements IHelloWorldService {

  public String getHelloMessage(String name) {
    return "Hello " + Optional.ofNullable(name).orElse("World!");
  }

}

Such a simple Web service is done, you can start the project with curl command calls to try, for example: curl XGET - i "http: / / 127.0.0.1:8080 / hello & # 63; name=Java", if the 1 cut goes well, you will get a response like the following:


HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 11
Date: Thu, 11 Jan 2018 09:45:38 GMT

Hello Java

Use custom annotations to count the execution time of a method

Define a note to count the execution time of a method.


package com.craneyuan.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnalysisActuator {
  String note() default "";
}

Then define 1 aspect to handle the annotation you just defined.


package com.craneyuan.aspect;

import com.craneyuan.annotation.AnalysisActuator;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AnalysisActuatorAspect {
  final static Logger log = LoggerFactory.getLogger(AnalysisActuatorAspect.class);

  ThreadLocal<Long> beginTime = new ThreadLocal<>();

  @Pointcut("@annotation(analysisActuator)")
  public void serviceStatistics(AnalysisActuator analysisActuator) {
  }

  @Before("serviceStatistics(analysisActuator)")
  public void doBefore(JoinPoint joinPoint, AnalysisActuator analysisActuator) {
    //  Record the arrival time of the request 
    beginTime.set(System.currentTimeMillis());
    log.info("cy666 note:{}", analysisActuator.note());
  }

  @After("serviceStatistics(analysisActuator)")
  public void doAfter(AnalysisActuator analysisActuator) {
    log.info("cy666 statistic time:{}, note:{}", System.currentTimeMillis() - beginTime.get(), analysisActuator.note());
  }

}

Finally, just add the @AnalysisActuator annotation to any method that needs to count the execution time.


package com.craneyuan.service.impl;

import com.craneyuan.annotation.AnalysisActuator;
import com.craneyuan.service.IHelloWorldService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class HelloWorldServiceImpl implements IHelloWorldService {

  @AnalysisActuator(note = " Get the chat message method ")
  public String getHelloMessage(String name) {
    return "Hello " + Optional.ofNullable(name).orElse("World!");
  }

}

To start the project, call 1 randomly with the curl command, and if it goes well, you will see the log printed on the section.


...
cy666 statistic time:4, note: Get the chat message method 

Related articles: