看了很多关于spring boot 的源码分析,感觉都只在关注面试题, 关键注解,但是这样并无法达到对其启动的深刻理解,只是死板的记忆,,过了几天又忘了 ,所以我在看完之后打算把他记下来,以供以后复习使用。重点是一定要自己点一遍
1. 核心注解SpringBootApplication
@SpringBootConfiguration – 配置类 就是@Configuration
@EnableAutoConfiguration – 核心注解,通过@import + @Configuration + @Bean 导入第三方jar
@ComponentScan – 包扫描,默认扫当前启动类所在包一下的所有注解 ,将其加入IOC
2. 启动类SpringApplication.run()
new SpringApplication(primarySources).run(args);
启动类Run方法可以分为两部分
new SpringApplication(primarySources)
run(args);方法
- 第一部分new SpringApplication(primarySources)
primarySources == HelloworldApplication.class 启动类 类型
@SpringBootApplication
public class HelloworldApplication {
public static void main(String[] args) {
SpringApplication.run(HelloworldApplication.class, args);
}
}
进入启动类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
重点 分析三句:
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
1.1 getBootstrapRegistryInitializersFromSpringFactories()
private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
getSpringFactoriesInstances(Bootstrapper.class).stream()
.map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
.forEach(initializers::add);
initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
return initializers;
}
核心方法: getSpringFactoriesInstances()
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
SpringFactoriesLoader.loadFactoryNames()
通过classloader 的双亲委派机制加载所有jar中的META-INF/spring.factories文件
并将其读取存入cache中以便下次取用。
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
其中存储的是spring 启动中重要的类及其对应子类
在启动中接下来药用到的就是ApplicationContextInitializer 和 ApplicationListener , 最重要的还有EnableAutoConfiguration , 可以看到他又130个子类(后面再说)
当他初始化好之后,会进行一个过滤loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
获取当前传入class的配置,当前是Bootstrapper.class , 但是在配置文件中并没有他的配置。所以instance最终为0
最后返回到最外层getBootstrapRegistryInitializersFromSpringFactories
此时bootstrapRegistryInitializers还没有值(size为0)
1.2 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
同样的逻辑,这次会取出所有ApplicationContextInitializer.class的子类
随后通过createSpringFactoriesInstances , 为所有的子类创建一个空的实例
- 第二部分run(args);方法