概述 前面我们了解了spring框架中的@Configuration配置和@ConfigurationProperties加载外部配置注解的使用。那么在Spring boot项目中,应用上下文又是如何找到那么多配置并加载初始化好的呢?
@SpringBootApplication spring boot项目推荐大家在主类中标注@SpringBootApplication这个注解,我们来看看它的源码:
@Target
(ElementType.
TYPE
)
@Retention
(RetentionPolicy.
RUNTIME
)
@Documented
@Inherited
@SpringBootConfiguration //配置
@EnableAutoConfiguration //启用自动配置
//组件扫描
@ComponentScan
(excludeFilters =
@Filter
(type = FilterType.
CUSTOM
, classes = TypeExcludeFilter.
class
))
public
@
interface
SpringBootApplication
{
//需要排除的自动配置类
Class<?>[] exclude()
default
{};
//需要排除的自动配置类类名
String[] excludeName()
default
{};
//扫描包路径
@AliasFor
(annotation =
ComponentScan
.
class
, attribute =
“basePackages”
)
String[] scanBasePackages()
default
{};
//扫描包路径类
@AliasFor
(annotation =
ComponentScan
.
class
, attribute =
“basePackageClasses”
)
Class<?>[] scanBasePackageClasses()
default
{};
}
@EnableAutoConfiguration 我们发现一个配置开关注解,名字叫@EnableAutoConfiguration,看看它的源码:
@Target
(ElementType.
TYPE
)
@Retention
(RetentionPolicy.
RUNTIME
)
@Documented
@Inherited
@AutoConfigurationPackage
@Import
(EnableAutoConfigurationImportSelector.
class
)
public
@
interface
EnableAutoConfiguration
{
//是否启用自动配置的总开关名
String
ENABLED_OVERRIDE_PROPERTY
=
“spring.boot.enableautoconfiguration”
;
//需要排除的自动配置类
Class<?>[] exclude()
default
{};
//需要排除的自动配置类类名
String[] excludeName()
default
{};
}
EnableAutoConfigurationImportSelector 我们看到有一个@Import导入了选择器
EnableAutoConfigurationImportSelector.
class,看看它的源码:
public class
EnableAutoConfigurationImportSelector
implements
DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
…
protected boolean
isEnabled(AnnotationMetadata metadata) {
if
(getClass().equals(EnableAutoConfigurationImportSelector.
class
)) {
//环境变量中的开关配置,如果没有默认开启
return this
.
environment
.getProperty(
EnableAutoConfiguration
.
ENABLED_OVERRIDE_PROPERTY
, Boolean.
class
,
true
);
}
return true
;
}
//spring工厂类
protected
Class<?> getSpringFactoriesLoaderFactoryClass() {
return
EnableAutoConfiguration
.
class
;
}
//通过spring工厂类加载工厂配置
protected
List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.
loadFactoryNames
(
getSpringFactoriesLoaderFactoryClass(), 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;
}
@Override
public
String[] selectImports(AnnotationMetadata metadata) {
//如果开关关闭,则返回空数组,标识不导入任何自动配置
if
(!isEnabled(metadata)) {
return
NO_IMPORTS
;
}
try
{
//获取EnableAutoConfiguration注解的属性,用户自定义的配置
AnnotationAttributes attributes = getAttributes(metadata);
//获取spring工厂默认配置
List<String> configurations = getCandidateConfigurations(metadata,
attributes);
//去重
configurations = removeDuplicates(configurations);
//找到用户自定义的例外配置
Set<String> exclusions = getExclusions(metadata, attributes);
//删除对应的例外配置
configurations.removeAll(exclusions);
//排序,因为自动配置会有bean引用依赖,还考虑Order,ConfigurationBefore等
//先按字母排序,再根据order排序,再根据ConfigurationBefore等排序
configurations = sort(configurations);
//输出满足条件的配置项目
recordWithConditionEvaluationReport(configurations, exclusions);
return
configurations.toArray(
new
String[configurations.size()]);
}
catch
(IOException ex) {
throw new
IllegalStateException(ex);
}
}
@Override
public int
getOrder() {
return
Ordered.
LOWEST_PRECEDENCE
–
1
;
}
} 我们看到首先这个导入选择器实现了DeferredImportSelector接口,会等到所有的bean都初始化完成后,再进行选择处理,通常用在用户未自定义配置的默认配置和默认Bean处理。结合它的优先级
Ordered.
LOWEST_PRECEDENCE
–
1,说明了它是一个后置的导入选择器。 然后我们来看getCandidateConfigurations这个方法,里面用到了工具类SpringFactoriesLoader
SpringFactoriesLoader
public abstract class
SpringFactoriesLoader {
public static final
String
FACTORIES_RESOURCE_LOCATION
=
“META-INF/spring.factories”
;
public static
List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
//spring工厂名字,这里是
EnableAutoConfiguration
.
class
String factoryClassName = factoryClass.getName();
try
{
//搜索类路径下所有的META-INF/spring.factories文件
Enumeration<URL> urls = (classLoader !=
null
? classLoader.getResources(
FACTORIES_RESOURCE_LOCATION
) :
ClassLoader.
getSystemResources
(
FACTORIES_RESOURCE_LOCATION
));
List<String> result =
new
ArrayList<String>();
while
(urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.
loadProperties
(
new
UrlResource(url));
//获取
EnableAutoConfiguration
.
class
类路径为key的配置
String factoryClassNames = properties.getProperty(factoryClassName);
//用,作为分隔符解析为字符串数组
result.addAll(Arrays.
asList
(StringUtils.
commaDelimitedListToStringArray
(factoryClassNames)));
}
return
result;
}
catch
(IOException ex) {
throw new
IllegalArgumentException(
“Unable to load [”
+ factoryClass.getName() +
“] factories from location [”
+
FACTORIES_RESOURCE_LOCATION
+
“]”
, ex);
}
}
….
}
我们打开spring的jar包,来找到一个
META-INF/spring.factories文件看看: spring-boot-autoconfigure-1.4.5.RELEASE.jar!\META-INF\spring.factories
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\ org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
这就是Spring boot自动配置的设计,从配置文件加载常用的默认配置。在这些配置里面,我们看到了熟悉的
ConfigurationPropertiesAutoConfiguration。
打开这个自动配置看看
@Configuration
@EnableConfigurationProperties
public class
ConfigurationPropertiesAutoConfiguration {
}
我们找到了久违的开关注解
@EnableConfigurationProperties
这样就能解释,当我们启动了spring boot主类之后,激活了各种自动配置,spring会把对应的默认bean都构建好,我们无需配置就可以直接使用了。 Spring @AutoConfiguration源码详解