Origin 003 | Get on the SpringBoot Transaction Ideas Campaign

Posted by julien on Sat, 07 Dec 2019 12:53:44 +0100

Special Car Introduction

This is a special bus going to the Spring Boot Transaction Ideas. In the last article, we detailed the principles of Spring Boot Transaction implementation in the Spring Boot Transaction Source Analysis Train [1], which is based on the previous one.

Before the battle, let's review the main points of the last article:

  • Postprocessor: Intercept and process beans
  • Faces: consisting of points of tangency and notifications
  • Tangent: Used to match matching classes and methods
  • Notification: for proxy processing

Special Car Problem

  • How do I intercept and process beans with a back-end processor?
  • How do I define the facets?
  • How do I define a tangent point?
  • How do I define notifications?
  • How to achieve automatic configuration?

Special Car Analysis

The implementation is based on Spring Boot and requires the following dependencies to be added

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

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

Define in turn according to the questions mentioned above

Define a bean postprocessor, with special attention to not having to redefine if transaction attributes are used in your project

/**
 * Be sure to declare Infrastructure AdvisorAutoProxyCreator for post-processing of bean s
 *
 * @return
 */
@Bean
public InfrastructureAdvisorAutoProxyCreator infrastructureAdvisorAutoProxyCreator() {
    return new InfrastructureAdvisorAutoProxyCreator();
}

Define Faces

public class BeanFactorySystemLogAdvisor extends AbstractBeanFactoryPointcutAdvisor {

    /**
    * Define the point of tangency
    */
    private final SystemLogPointcut point = new SystemLogPointcut();

    @Override
    public Pointcut getPointcut() {
        return this.point;
    }
}

Define the point of tangency

public class SystemLogPointcut extends StaticMethodMatcherPointcut {

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        // Find @SystemLog annotation property on class
        AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
                targetClass, SystemLog.class, false, false);
        if (Objects.nonNull(attributes)) {
            return true;
        }
        // The @SystemLog annotation property on the lookup method
        attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
                method, SystemLog.class, false, false);
        return Objects.nonNull(attributes);
    }
}

Define Notifications

@Slf4j
public class SystemLogInterceptor implements MethodInterceptor, Serializable {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        String className = method.getDeclaringClass().getSimpleName();
        String methodName = method.getName();
        log.info("======[" + className + "#" + methodName + " method begin execute]======");
        Arrays.stream(invocation.getArguments()).forEach(argument -> log.info("======[execute method argument: " + argument + "]======"));
        Long time1 = Clock.systemDefaultZone().millis();
        Object result = invocation.proceed();
        Long time2 = Clock.systemDefaultZone().millis();
        log.info("======[method execute time: " + (time2 - time1) + "]======");
        return result;
    }
}

Automatic Configuration

@Configuration
public class ProxySystemLogConfiguration {

    /**
    * Define Faces
    * Be sure to specify the @Role comment here
    *
    * @return
    */
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Bean
    public BeanFactorySystemLogAdvisor beanFactorySystemLogAdvisor() {
        BeanFactorySystemLogAdvisor advisor = new BeanFactorySystemLogAdvisor();
        advisor.setAdvice(systemLogInterceptor());
        return advisor;
    }

    /**
    * Define Notifications
    *
    * @return
    */
    @Bean
    public SystemLogInterceptor systemLogInterceptor() {
        return new SystemLogInterceptor();
    }

    /**
    * Be sure to declare Infrastructure AdvisorAutoProxyCreator for post-processing of bean s
    *
    * @return
    */
    @Bean
    public InfrastructureAdvisorAutoProxyCreator infrastructureAdvisorAutoProxyCreator() {
        return new InfrastructureAdvisorAutoProxyCreator();
    }
}

Definition Notes

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLog {
}

Special Vehicle Integration Business

Define Controller

@RestController
public class SystemLogController {

    @Autowired
    private SystemLogService systemLogService;

    @GetMapping("/log")
    public String hello(@RequestParam("name") String name) throws InterruptedException {
        return systemLogService.log(name);
    }
}

Define business methods

@Slf4j
@Service
public class SystemLogService {

    @SystemLog
    public String log(String name) throws InterruptedException {
        log.info("Execute business methods");
        TimeUnit.SECONDS.sleep(1);
        return "hello " + name;
    }
}

Define Startup Class

@SpringBootApplication
public class TransactionImitateApplication {

    public static void main(String[] args) {
        SpringApplication.run(TransactionImitateApplication.class, args);
    }
}

Visit http://localhost:8080/log?name=advisor

View Console

2019-08-23 11:13:36.029  INFO 23227 --- [nio-8080-exec-1] c.b.example.config.SystemLogInterceptor  : ======[SystemLogService#Log method begin execute]=========================================[execute method:argument:advisor]=====================2019-08-23 11 11:13:36.038 INFO 23227 --- [nio-8080-8080-exec-13:13:36.030 INFO 2311 11 11 11:13:36.030 INFO 2322227 --- [nio-8080-13:13:13:13:36.030 exec.boot.example.service.SystemLogService LogService:execute business method 2019-0880-23 11:13:37.038 INFO 23227 --- [nio-8080-eXec-1] c.b.example.config.SystemLogInterceptor: ======[method execute time:1004]======

You can see that log slicing is accomplished by simulating the implementation of the @Transaction annotation.

Special Vehicle Summary

  • First we need to define a Bean Post Processor to intercept processing beans
  • Then define the facet, and define the point of tangency in the facet
  • Logic to implement a cut-in in a point of tangency, such as here our implementation logic is to find out if a class or method has the @SystemLog annotation
  • Define notifications to complete agent work
  • Auto-assemble, declare our facets, notifications, Bean post-processor in the configuration class
  • Integrated Business

Special Vehicle Review

Looking back at the first five questions:

  • How do I intercept and process beans with a back-end processor?Declare the postprocessor directly in the configuration class
  • How do I define the facets?Inherit AbstractBeanFactoryPointcutAdvisor and declare it in the configuration class
  • How do I define a tangent point?Inherit StaticMethodMatcherPointcut to implement matches method
  • How do I define notifications?Implement MethodInterceptor interface and invoke method
  • How to achieve automatic configuration?Customize the configuration class to declare all Bean s that need to be added to the container

Last

Teacher, [Advanced Java architect], wins 15W+ programmer's attention on all platforms in just one year, focusing on sharing 20 advanced architecture topics such as Java Advanced, Architecture Technology, High Concurrency, Micro Services, BAT Interview, redis, JVM Tuning, Springboot Source Code, mysql Tuning, etc. and focusing on [Advanced Java architect] replying to [Architecture] for a complete set of 2019 architect videos.

Reload instructions: Be sure to indicate the source (this article was first published under Public Number: [Advanced java architect]

Topics: Java Spring Lombok Redis