SpringBoot自动装配原理以及run执行过程

SpringBoot自动装配

@SpringBootApplication //从这个注解开始分析
public class DemoApplication {

   public static void main(String[] args) {
       SpringApplication.run(DemoApplication.class, args);
  }

}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration //这个注解底层就是使用了configuration注解,意味着SpringBootApplication注解就是一个配置类
@EnableAutoConfiguration//自动装配开启注解
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) //包扫描注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

 

 

 

AutoConfigurationPackage注解分析

AutoConfigurationPackage注解的作用是会把springbootApplication注解标注的类所在包名拿到,并且对该子包进行扫描

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class) //将Register这个组件导入到容器中
public @interface AutoConfigurationPackage {
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}

@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}

}

registerBeanDefinitions方法中,metadata就是标记注解的元数据信息 我们可以在这里下断点调试一下

可以发现确实获取到了当前启动类的包名,而且看下面metadata中的信息确实获取到了启动类

 

 

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
if (registry.containsBeanDefinition(BEAN)) {
BasePackagesBeanDefinition beanDefinition = (BasePackagesBeanDefinition) registry.getBeanDefinition(BEAN);
beanDefinition.addBasePackages(packageNames);
}
else {
registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames));
}
}

在具体的这个register方法中,将这个报名封装成了一个BeanDefinition对象并且注册到了IOC容器中

 

 

AutoConfigurationImportSelector分析

 

我们进入到AutoConfigurationImportSelector类中的selectImports方法,这个方法就是告诉springboot需要导入哪些组件

public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

在这个方法里,加载配置文件,从中获取所有支持自动装配的类的条件,springboot会将收集好的@Configuration进行一次过滤进而剔除不满足条件的配置类。我们进getAutoConfigurationEntry这个方法看一下

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations); //去除重复的配置类
Set<String> exclusions = getExclusions(annotationMetadata, attributes); //获取不希望被自动配置的类
checkExcludedClasses(configurations, exclusions); //交验排除,排除的类必须是自动装配类否则会抛异常
configurations.removeAll(exclusions);//移除所有不希望被自动配置的类
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}

这里的getCandidateConfigurations是重点,用来获取默认支持的自动配置类列表,我们进去详细看一下

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;
}
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;
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

 

这个result返回之后封装成了list集合,泛型是String,其实就是jar包下META-INF/spring.factories中的全类名集合。

判断某一个类是否需要被加载的两个方式:

1.根据spring-autoconfigure-metadata.preperties进行判断

2.根据@Conditional注解进行判断看是否满足

private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners) {
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}

所有需要配置的类都过滤完毕之后就会触发事件监听器

 

总结

通过将AutoConfigureationImportSelector类导入到容器中。AutoConfigureationImportSelector通过selectImports方法执行的过程中,会使用内部的工具类SpringFactorLoader,查找classpath上所有jar包中的spring.factories进行加载,实现将配置类信息交给springfactory加载器进行一系列的容器创建过程

 

 

ComponentScan注解分析

这个注解具体扫描的包路径由spring boot项目主程序启动类所在包决定,再扫描过程中由前面的AutoConfigurationPackage注解进行解析,从而得到spring boot项目主程序启动类所在包的具体位置

 

 

 

 

 

 

 

SpringBoot执行原理分析

 

SpringApplication实例化过程

public static void main(String[] args) {
       SpringApplication.run(DemoApplication.class, args);
  }

进入这个run方法,这是一个重载方法,我们看他最终执行的run方法

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}

创建SpringApplication类的实例,然后调用他的run方法

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(); //判断是哪种mvc
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
  //设置初始化器Initializer,最后会调用这些初始化器
  //所谓初始化器就是org.springframework.context.ApplicationContextInitializer的实现类,在SPring上下文被刷新之前执行
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  //设置监听器Listener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  //初始化mainApplicationClass属性,用于推断并设置项目main()方法启动的主程序类
this.mainApplicationClass = deduceMainApplicationClass();
}
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}

 

run方法解析

public ConfigurableApplicationContext run(String... args) {
  //StopWatch是spring的一个工具类,用于统计run方法的启动过程时长
StopWatch stopWatch = new StopWatch();
stopWatch.start();
 
  //初始化应用上下文和异常报告集合
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
   
  //第一步:获取并启动监视器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
           //创建ApplicationArguments对象,初始化默认应用参数类,args是Spring应用的命令行参数,该参数可以在Spring应用中被访问,如--server.port
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
           
           //第二步:项目运行环境的预配置
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
           
           //Banner打印器,就是springboot项目启动时侯的那个图表
Banner printedBanner = printBanner(environment);
           
           //第三步:创建Spring容器
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
           
           //第四步:Spring容器前置处理
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
           
           //第五步:刷新容器
refreshContext(context);
           
           //第六步:后置处理器,扩展接口,默认为空,如果有自定义需求,可以重写这个方法
afterRefresh(context, applicationArguments);
stopWatch.stop();
           //打印springboot启动的时长日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
           
           //第七步:发出结束执行的时间通知
listeners.started(context);
           
           //第八步:执行Runners
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}

try {
           //第九步:发布应用上下文就绪事件
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
//第一步:获取并启动监视器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
//第二步:项目运行环境的预配置
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
  //创建或者获取环境,存在就直接返回,不存在就创建一个
ConfigurableEnvironment environment = getOrCreateEnvironment();
  //配置环境,配置PropertySources和active Profiles
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
  //listenser环境准备
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
  //将环境绑定到SpringApplication
bindToSpringApplication(environment);
  //如果不是web环境,将环境转换成StandardEnvironment
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
  //配置PropertySources对他自己的依赖
ConfigurationPropertySources.attach(environment);
return environment;
}
//第四步:Spring容器前置处理
//对整个上下文进行一个预处理,比如出发监听器的响应事件,加载资源,设置上下文环境等等
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
  //注册启动参数bean,将容器指定的参数封装成bean,注入容器
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
  //加载所有资源
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
  //加载启动类,将启动类注入容器,为后续开启自动化配置奠定基础
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
//第五步:刷新容器
private void refreshContext(ConfigurableApplicationContext context) {
  //注册钩子函数,当JVM关闭时关闭这个上下文
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
  //刷新容器,对整个IOC容器的初始化,包括资源的定位,解析,注册等等
refresh(context);
}
//第八步:执行Runners
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
  //获取所有ApplicationRunner的实现类
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
  //获取所有CommandLineRunner的实现类
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
  //遍历集合,执行逻辑
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}

 

posted @ 2021-06-21 11:41  头发少少少。  阅读(240)  评论(0)    收藏  举报