摘要

该文章只为了记录一些Spring的使用,比如自建starter、配置属性提示、自动注册Bean等操作

正文

该文章只为了记录一些Spring的使用,比如自建starter、配置属性提示、自动注册Bean等操作

本文涉及到的源码

一、starter添加属性提示

首先,建个配置类

java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@ConfigurationProperties(prefix = "person")
public class PersonProperties {

    /**
     * 姓名
     */
    private String name = "尸祖降臣";

    /**
     * 身价
     */
    private Double money = 1.0;

    /**
     * 生日
     */
    private String birth = "1970-01-01 00:00:00";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    public String getBirth() {
        return birth;
    }

    public void setBirth(String birth) {
        this.birth = birth;
    }
}

其次,添加依赖

xml
1
2
3
4
5
6
7
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <version>2.5.4</version>
    <optional>true</optional>
    <scope>provided</scope>
</dependency>

引用该starter,会发现已有提示。

image-20230605005959883.png

二、starter自动注册Bean

自动注册Bean,我目前使用到了两种方式

  1. spring.factories
    • 适用于bean较少的情况,指定自建配置类,进行bean的自动注册
  2. import
    • 适用于bean较多的情况

2.1 spring.factories

示例配置类

java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Configuration
@ConditionalOnClass(Log.class)
public class LogAutoConfiguration {

    private final Logger log = LoggerFactory.getLogger(LogAutoConfiguration.class);

    @Bean
    public LogHandler logHandler() {
        LogHandler logHandler = new LogHandler();
        log.debug("自动装配bean--日志切面处理器");
        return logHandler;
    }
}

配置spring.factories

将spring.factories放置到路径resources/META-INF下

properties
1
org.springframework.boot.autoconfigure.EnableAutoConfiguration=top.meethigher.log.LogAutoConfiguration

2.2 import批量注册bean

首先创建importSelector.properties

properties
1
2
serviceImplClass=top.meethigher.starter.importbean.impl.TestAImpl,\
top.meethigher.starter.importbean.impl.TestBImpl

如果类太多,可以直接使用如下脚本,在junit单元测试环境下,自动生成配置

java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

import org.junit.Test;

import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;

/**
 * 生成import Bean配置文件
 *
 * @author chenchuancheng github.com/meethigher
 * @since 2023/6/5 00:35
 */
public class GenerateImportProperties {

    private final static String serviceImplPath;

    static {

        String serviceImplRoot = "/target/classes/top/meethigher/starter/importbean/impl";
        String root = System.getProperty("user.dir").replace("\\", "/");
        serviceImplPath = root + serviceImplRoot;
    }


    @Test
    public void generateImportProperties() throws Exception {
        String serviceImplPackageName = "top.meethigher.starter.importbean.impl";
        String serviceImplClazz = "serviceImplClass=";
        List<Class<?>> serviceImplClasses = walkDir(serviceImplPath, serviceImplPackageName);

        StringBuilder sb = new StringBuilder();
        sb.append(generateConfig(serviceImplClazz, serviceImplClasses));
        System.out.println(sb.toString());
    }

    private List<Class<?>> walkDir(String root, String packageName) throws Exception {
        List<Class<?>> list = new LinkedList<>();
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(root), "*.class")) {
            for (Path path : stream) {
                String className = packageName + "." + path.getFileName().toString().replace(".class", "");
                Class<?> clazz = Class.forName(className);
                list.add(clazz);
            }
        }
        return list;
    }

    private String generateConfig(String prefix, List<Class<?>> classes) throws Exception {
        StringBuilder sb = new StringBuilder();
        sb.append(prefix);
        for (int i = 0; i < classes.size(); i++) {
            Class<?> clazz = classes.get(i);
            if (i == classes.size() - 1) {
                sb.append(clazz.getName())
                        .append("\n");
            } else {
                sb.append(clazz.getName())
                        .append(",")
                        .append("\\")
                        .append("\n");
            }
        }
        sb.append("\n");
        return sb.toString();
    }


}

核心就在于@Import注解

java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

import java.util.ResourceBundle;
import java.util.function.Predicate;

/**
 * 配合spring.factories实现自动装配
 * 
 * @author chenchuancheng github.com/meethigher
 * @since 2023/6/5 00:49
 */
@Configuration
@Import(ImportSelectorImpl.class)
public class AutoImportConfig {
}

/**
 * 导入
 *
 * @author chenchuancheng github.com/meethigher
 * @since 2023/6/5 00:45
 */
class ImportSelectorImpl implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        ResourceBundle rb = ResourceBundle.getBundle("importSelector");
        String serviceImplItems = rb.getString("serviceImplClass");
        String[] serviceImplArr = serviceImplItems.split(",");
        return serviceImplArr;
    }

    public String[] mergeArrays(String[] arr1, String[] arr2, String[] arr3) {
        String[] result = new String[arr1.length + arr2.length + arr3.length];
        System.arraycopy(arr1, 0, result, 0, arr1.length);
        System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
        System.arraycopy(arr3, 0, result, arr1.length + arr2.length, arr3.length);
        return result;
    }

    @Override
    public Predicate<String> getExclusionFilter() {
        return ImportSelector.super.getExclusionFilter();
    }
}

引用该starter,会发现已批量自动注册bean

image-20230605005139884.png

三、参考致谢

Spring系列之@import详解(bean批量注册)_spring @import_azhou的代码园的博客-CSDN博客

Spring boot starter 如何给配置添加idea 提示功能 spring-boot-configuration-processor_自定义starter让idea配置提示_Young丶的博客-CSDN博客