言成言成啊 | Kit Chen's Blog

Spring自动装配Bean那些事

发布于2023-06-05 00:55:21,更新于2023-06-05 01:07:39,标签:java  转载随意,文章会持续修订,请注明来源地址:https://meethigher.top/blog

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

本文涉及到的源码

一、starter添加属性提示

首先,建个配置类

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;
}
}

其次,添加依赖

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,会发现已有提示。

二、starter自动注册Bean

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

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

2.1 spring.factories

示例配置类

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下

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

2.2 import批量注册bean

首先创建importSelector.properties

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

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

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注解

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

三、参考致谢

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

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

发布:2023-06-05 00:55:21
修改:2023-06-05 01:07:39
链接:https://meethigher.top/blog/2023/spring-config/
标签:java 
付款码 打赏 分享
shift+ctrl+1可控制目录显示