什么是SpringBoot?
回答这个问题之前,我先回答一下什么是Spring?
Spring框架是一个开放源代码的应用框架,是针对Bean的生命周期进行管理的轻量级容器。
Spring是为了解决企业级应用开发的复杂性而创建的,主要的目的是“简化开发“。
Spring如何简化开发?
基于POJO的轻量级和最小入侵式编程。
通过IOC/DI和面向接口实现松耦合。
基于切面AOP策略和模板方法进行声明式编程。
通过切面和模板减少样式代码。
SpringBoot的出现就是进一步完善Spring的目的”简化开发“,提出了约定优于配置的思想,通过“自动装配”,实现了进一步的"简化开发"。
SpringBoot如何实现自动装配?
Spring实现配置的方式。可以分为三种:JavaConfig、XML、注解。
SpringBoot实现自动装配的方式是注解+JavaConfig。
SpringBoot启动类注解 @SpringBootApplication :
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // springboot的核心配置
@EnableAutoConfiguration // 自动装配默认启用
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
//... 部分代码可自行查看源码
}
@EnableAutoConfiguration 注解内部的代码如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 自动装配包
@Import({AutoConfigurationImportSelector.class}) // 导入 自动装配选择器类 由此深入了解
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class>[] exclude() default {};
String[] excludeName() default {};
}
AutoConfigurationImportSelector.class 部分代码:
/**
AutoConfigurationImportSelector.class 部分代码
简单剖析
*/
// 获得所有候选配置类的路径
protected List getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// 找到META-INF/spring.factories中的配置类的路径
List configurations = SpringFactoriesLoader
.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
// 断言一下这个list是否为空,如果为空就报错
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;
}
SpringFactoriesLoader.loadFactoryNames();
public static List loadFactoryNames(Class> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
// 核心是这个方法
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
loadSpringFactories();
// 这个方法就是把SpringBoot所有存在的自动装配的配置类的路径返回
// 同时存储到SpringFactoriesLoader.class 的 static final Map>> cache = new ConcurrentReferenceHashMap(); 容器中
private static Map> loadSpringFactories(ClassLoader classLoader) {
Map> result = (Map)cache.get(classLoader);
if (result != null) {
return result;
} else {
HashMap result = new HashMap();
try {
// SpringBoot把所有的自动装配的配置类都存放在META-INF/spring.factories
Enumeration urls = classLoader.getResources("META-INF/spring.factories");
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
String[] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames.length;
for(int var12 = 0; var12 < var11; ++var12) {
String factoryImplementationName = var10[var12];
((List)result.computeIfAbsent(factoryTypeName, (key) -> {
return new ArrayList();
})).add(factoryImplementationName.trim());
}
}
}
result.replaceAll((factoryType, implementations) -> {
return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
});
// 加入容器中
cache.put(classLoader, result);
return result;
} catch (IOException var14) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
}
}
}
spring..factories 概览
# AutoConfigureCache auto-configuration imports
org.springframework.boot.test.autoconfigure.core.AutoConfigureCache=\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
# AutoConfigureDataCassandra auto-configuration imports
org.springframework.boot.test.autoconfigure.data.cassandra.AutoConfigureDataCassandra=\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration
结论:
Springboot所有自动装配的类都是在启动的时候扫描进行加载,通过加载META-INF/spring.factories文件得到所有类的路径,然后通过@condition条件判断注解判断存在该jar包再进行自动加载。
具体的层级和实现具体看下图: