SpringBoot3 自定义 Starter

SpringBoot3 自定义 Starter

SpringBoo3 最简单自定义 Starter 步骤。

1. 启动一个空白模板项目

gradle或者maven项目
引入如下依赖:

implementation("org.springframework.boot:spring-boot-autoconfigure:3.5.0")

2. 手写自动配置类

package edu.tyut.config

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.BeanFactory
import org.springframework.boot.autoconfigure.AutoConfiguration
import org.springframework.boot.autoconfigure.AutoConfigurationPackages
import org.springframework.context.annotation.Bean

private const val BASE_PACKAGE: String = "basePackage"

/**
 * custom config
 */
@AutoConfiguration
internal open class CustomAutoConfig {
    private val logger: Logger = LoggerFactory.getLogger(this.javaClass)
    @Bean(value = [BASE_PACKAGE])
    internal open fun getBasePackage (
        beanFactory: BeanFactory
    ): String {
        val packages: List<String> = AutoConfigurationPackages.get(beanFactory)
        logger.info("CustomAutoConfig AutoConfiguration Packages: $packages")
        return packages.firstOrNull() ?: "edu.tyut"
    }
}

3. 注册自动配置类

在文件resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports下注册:

edu.tyut.config.CustomAutoConfig

End, 怎么样是不是非常简单

原理解析

1. 启动类的注解@SpringBootApplication

源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}

2. @EnableAutoConfiguration

源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}

3. AutoConfigurationImportSelector

源码如下:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
	private final Class<?> autoConfigurationAnnotation;
	AutoConfigurationImportSelector(Class<?> autoConfigurationAnnotation) {
		this.autoConfigurationAnnotation = (autoConfigurationAnnotation != null) ? autoConfigurationAnnotation
				: AutoConfiguration.class;
	}
...
	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		ImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation,
				getBeanClassLoader());
		List<String> configurations = importCandidates.getCandidates();
		Assert.state(!CollectionUtils.isEmpty(configurations),
				"No auto configuration classes found in " + "META-INF/spring/"
						+ this.autoConfigurationAnnotation.getName() + ".imports. If you "
						+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}
...
}

代码解读
查看该类构造函数可以发现其有一个成员变量autoConfigurationAnnotation,其值为org.springframework.boot.autoconfigure.AutoConfiguration.
getCandidateConfigurations的参数为即为org.springframework.boot.autoconfigure.AutoConfiguration.

4. org.springframework.boot.context.annotation.ImportCandidates

源码如下:

public final class ImportCandidates implements Iterable<String> {
...
	public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
		Assert.notNull(annotation, "'annotation' must not be null");
		ClassLoader classLoaderToUse = decideClassloader(classLoader);
		String location = String.format(LOCATION, annotation.getName());
		Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
		List<String> importCandidates = new ArrayList<>();
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			importCandidates.addAll(readCandidateConfigurations(url));
		}
		return new ImportCandidates(importCandidates);
	}
}

代码解读:
找到类路径下所有的META-INF/spring/full-qualified-annotation-name.imports文件,读取内容(自动配置类的全限定名), 如果在自动配置类没有org.springframework.boot.autoconfigure.AutoConfiguration注解,会抛出IllegalArgumentException异常。
META-INF/spring/full-qualified-annotation-name.imports文件 -> URL -> BufferedReader -> ImportCandidates.

5. ImportCandidates

ImportCandidates包含了所有的自动配置类,SpringBoot会对其进行进一步的处理。

End 本文分享结束, 有什么不足还请大家指出

posted @ 2025-06-07 13:12  爱情丶眨眼而去  阅读(56)  评论(0)    收藏  举报