当我们初始化一个 SpringBoot 工程,查看 pom.xml配置,发现有如下 依赖
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.5RELEASEversion>
parent>
根据 maven 的继承依赖关系,点进去发现还会继续依赖
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.1.5.RELEASEversion>
<relativePath>../../spring-boot-dependenciesrelativePath>
parent>
再点进去可以看到最终依赖了spring-boot-dependencies
依赖文件,也就是说 SpringBoot的核心依赖在父工程中,这个文件定义了好多jar 包以及各个 Jar 包的 版本,我们写或引入一些 SpringBoot 依赖的时候不需要指定版本就因为有这些版本库。
注意我上面用的是 2.1.5.RELEASE 版本,可以直接查看依赖继承关系,如果是 2.2.2.RELEASE(最新版)点不了,改成从 spring-boot-starter-web 启动器进源码才可以查看
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
@SpringBootApplication
public class SpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplication.class, args);
}
}
@SpringBootApplication 这个注解它就标注了这是一个 SpringBoot 的应用
@SpringBootApplication 是一个组合注解,点进去发现由多个注解组成
@SpringBootConfiguration
@EnableAutoConfiguration
//扫描当前启动类同等级的包
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class})})
public @interface SpringBootApplication {
}
@SpringBootConfiguration 表明它是一个 SpringBoot 配置,查看源码发现核心注解由 @Configuration 组成,而 @Configuration 是个 Spring 注解,查看 @Configuration 源码发现最终是个 @Component (组件)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
}
@EnableAutoConfiguration 自动配置,查看其源码
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
@AutoConfigurationPackage 就是自动配置包,查看其源码,发现使用 @Import 引入了 Registrar 这个类
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
查看 Registrar 类源码
public abstract class AutoConfigurationPackages {
private static final Log logger = LogFactory.getLog(AutoConfigurationPackages.class);
private static final String BEAN = AutoConfigurationPackages.class.getName();
public AutoConfigurationPackages() {
}
public static boolean has(BeanFactory beanFactory) {
return beanFactory.containsBean(BEAN) && !get(beanFactory).isEmpty();
}
public static List<String> get(BeanFactory beanFactory) {
try {
return ((AutoConfigurationPackages.BasePackages)beanFactory.getBean(BEAN, AutoConfigurationPackages.BasePackages.class)).get();
} catch (NoSuchBeanDefinitionException var2) {
throw new IllegalStateException("Unable to retrieve @EnableAutoConfiguration base packages");
}
}
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
} else {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(AutoConfigurationPackages.BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(2);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
}
@Import(AutoConfigurationImportSelector.class) 则引入了 AutoConfigurationImportSelector 类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
private static final AutoConfigurationImportSelector.AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationImportSelector.AutoConfigurationEntry();
private static final String[] NO_IMPORTS = new String[0];
private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private ClassLoader beanClassLoader;
private ResourceLoader resourceLoader;
public AutoConfigurationImportSelector() {
}
//选择我们在 pom.xml 文件中引入的 jar 包或 组件
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
//获取自动配置实体
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//获取候选配置
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
//META-INF/spring.factories 是自动配置的核心文件
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
//EnableAutoConfiguration 这个类就是我们上文分析过的自动导入配置类,
//这样就可以获取到被这个注解标注的类的所有配置
//而 @SpringBootApplication 注解就继承了这个注解
//也即获取了主启动类加载的所有组件(绕了很远...)
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
}
关于spring.factories: 它是一个properties文件,它位于classpath:/META-INF/目录里面,每个jar包都可以有spring.factories的文件。Spring 提供工具类 SpringFactoriesLoader 负责加载、解析文件,如spring-boot-auto-configure-2.2.0.RELEASE.jar里面的META-INF目录里面就有spring.factories文件
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
.....
再看看 getCandidateConfigurations()方法中的 SpringFactoriesLoader.loadFactoryNames() 源码
public final class SpringFactoriesLoader {
//loadFactoryNames方法获取所有的加载配置
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
//加载项目资源
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
//遍历了所有的自动配置,封装成 properties 供我们使用
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
。。。。。。
}
cache.put(classLoader, result);
return result;
}
}
}
}
spring.factories 中那么多的配置类,有的并没有生效,需要导入对应的 starter 才能有作用,比如随便找个 AopAutoConfiguration 这个配置类,查看其源码,只有满足了 @ConditionalOnXXXX 注解里面的条件才会生效
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnProperty(
prefix = "spring.aop",
name = {"auto"},
havingValue = "true",
matchIfMissing = true
)
public class AopAutoConfiguration {
}
再比如的源码,只要满足 @ConditionalOnClass 条件即会生效
@Configuration( proxyBeanMethods = false)
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@EnableConfigurationProperties({DataSourceProperties.class})
@Import({DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class})
public class DataSourceAutoConfiguration {
}
根据上文分析,SpringBoot 会加载 spring.factories 的所有自动类,以 DataSourceAutoConfiguration 这个配置类来说,如果 pom 文件有对应的启动类,它就会生效,那么就会通过 @EnableConfigurationProperties 加载默认的配置文件,从源码可以看出默认的配置文件是 DataSourceProperties ,假如我们在 yml 中重新配置了某些属性,比如 jdbc.name、jdbc.username、jdbc.password…,SpringBoot 会读取这些属性并覆盖默认属性。
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
private ClassLoader classLoader;
private String name;
private boolean generateUniqueName;
private Class<? extends DataSource> type;
private String driverClassName;
private String url;
private String username;
private String password;
private String jndiName;
....
}
SpringBoot 所有自动配置都是在启动的时候扫描并加载,spring.factories 所有的自动类配置都得了这里,但是不一定会生效,要判断条件是否成立(通过 @ConditionalOnXXXX 注解),只要导入了对应的 starter 就有对应的启动器了,有了启动器,自动装配就会生效,然后就配置成功。