Others write to start from 0 to realize xxx, I start from -1 to be more awesome.

Today, let's start by teaching you how to implement a middleware.

New Project

First, we create a new multi-module project for testing.

The project contains two modules, test-infra development of user middleware module, demo for testing.

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aixiaoxian.infra</groupId>
    <artifactId>aixiaoxian-infra</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <name>aixiaoxian-infra</name>
    <description>aixiaoxian-infra</description>
    <packaging>pom</packaging>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <modules>
        <module>demo</module>
        <module>test-infra</module>
    </modules>

    <dependencies>

    </dependencies>

    <build>
        <plugins>
            <!-- Source -->
            <plugin>
                <artifactId>maven-source-plugin</artifactId>
                <inherited>true</inherited>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

development middleware

The project creation is OK, and then start to develop the simplest middleware.

Create a META-INFA/spring.factories file in the resources directory for automatic assembly, don't ask me what is automatic assembly, and then configure an automatic assembly class.

 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.aixiaoxian.testInfra.config.TestConfiguration

Implement TestConfiguration , the easiest way, directly use @Bean annotation to declare a bean to be managed by Spring.

 @Configuration
public class TestConfiguration implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {
    private Environment environment;

    @Bean
    public TestManager getTestManager() {
        return new TestManager();
    }
  
   @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

}

Then implement the processing part of the real middleware logic TestManager .

 @Slf4j
public class TestManager {

    public TestManager() {
        init();
    }

    public void init(){
        log.info("TestManager start");
    }
}

In this case, the simplest middleware has been developed, just add it to the demo module and start the test.

 <dependency>
   <groupId>com.aixiaoxian.infra</groupId>
   <artifactId>test-infra</artifactId>
   <version>0.0.1-SNAPSHOT</version>
 </dependency>

change posture

Bean 53ac0c54417465a3578e7a4962444314--- , BeanDefinitionRegistryPostProcessor ,让TestConfiguration去实现它,重写postProcessBeanDefinitionRegistry ,注册一个新的Bean aiManager , this is also OK, there are many ways to write it, so I won't repeat it.

 @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
    BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(AiManager.class);
    beanDefinitionBuilder.addConstructorArgValue(this.environment);
    beanDefinitionRegistry.registerBeanDefinition("aiManager", beanDefinitionBuilder.getBeanDefinition());
}
 @Slf4j
public class AiManager {
    private Environment environment;

    public AiManager(Environment environment) {
        this.environment = environment;

        init();
    }

    public void init(){
        log.info("AiManager start");
    }
}

change posture

With a basic understanding of Bean creation by autowiring, what should I do if I want to declare an annotation for others to use?

First create an annotation, notice that I used the @Import annotation, TestImportSelector implemented TestImportSelector interface.

 @Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({TestImportSelector.class})
@Documented
public @interface TestAnnotation {
}

public class TestImportSelector implements DeferredImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{AnnotationConfiguration.class.getName()};
    }
}

AnnotationConfiguration writing method is also very simple, which also realizes automatic assembly. Of course, you can achieve the same effect if you use the above writing method, but it is recommended to write it like this, don't ask, just ask.

 public class AnnotationConfiguration implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(AnnotationManager.class);
        beanDefinitionRegistry.registerBeanDefinition("annotationManager", beanDefinitionBuilder.getBeanDefinition());
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

@Slf4j
public class AnnotationManager {

    public AnnotationManager() {
        init();
    }

    public void init(){
        log.info("AnnotationManager start");
    }
}

Finally, put our annotation on the demo startup class.

 @SpringBootApplication
@TestAnnotation
public class DemoApplication {

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

Finally we can see the output:

 2022-06-21 19:05:07.433  INFO 4598 --- [           main] c.a.testInfra.manager.TestManager        : TestManager start
2022-06-21 19:05:07.456  INFO 4598 --- [           main] c.a.testInfra.manager.AiManager          : AiManager start
2022-06-21 19:05:07.456  INFO 4598 --- [           main] c.a.testInfra.manager.AnnotationManager  : AnnotationManager start

Okay, that's it, I guess, no one needs this source code? For the sake of the following articles, I will write this foreshadowing and end.


艾小仙
206 声望69 粉丝