实现是启动
然后一直往下,可以看到SpringApplication的主要逻辑:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
这里主要关注一些主干方法:
1、 context = this.createApplicationContext();
debug进去可以看到这里获取到的类是AnnotationConfigServletWebServerApplicationContext:
看其初始化方法
public AnnotationConfigServletWebServerApplicationContext() {
this.annotatedClasses = new LinkedHashSet();
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
这两个一个是读取器,一个是扫描器,先来看AnnotatedBeanDefinitionReader 的初始化:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
this.beanNameGenerator = new AnnotationBeanNameGenerator();
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, (ResourceLoader)null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
除了一些基本赋值,主要是AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)注册了5个BeanFactoryPostProcessor的Spring容器中;
其中这里面主要是ConfigurationClassPostProcessor类,实现了BeanDefinitionRegistryPostProcessor接口,此接口继承了BeanFactoryPostProcessor:
2、先往下看:this.refreshContext(context);
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
关于Bean加载以及初始化的一大堆逻辑就在此了。
关于这个方法的整体了解可以看下我的这篇文章:https://blog.csdn.net/qq_25179481/article/details/100188594
这里我们以自动加载为主要目标来找到实现方法:我们前面有提到,实现了
BeanDefinitionRegistryPostProcessor的ConfigurationClassPostProcessor,这里我们直接来看其的执行:通过
this.invokeBeanFactoryPostProcessors()
直接debug来到其的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法:
可以看到现在已经注册了7个Bean:
其中有一个thymeleafApplication,就是我们的启动类,有加一个SpringBootApplication的组合注解(关于注解就不展开了),现在会将其筛选出来,因为要使用这个注解
这里主要就是parser.parse(candidates)方法,这里面会有复杂的循环调用,因为@Configuration、@Import等注解需要循环调用去获取对应的信息,就不具体展开来讲了。我们看主要的方法:
一、ConfigurationClassParser类的processConfigurationClass方法:
我们可以看到现在这个BeanDefinition已经变成了一个对应的Configuration,其中annotations是这个注解有什么属性,就是根据这些去进行对应的解析的,正确来说是根据注解去获取这些属性的值。(以下整理可能来自来ConfigurationClassParser类的不同方法),如
1、Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
其中ComponentScan、ComponentScans等这些都是注解
2、if (candidate.isAssignable(ImportSelector.class))
3、importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
4、
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
return metadata.isAnnotated(Configuration.class.getName());
}
等就是根据这些注解加上循环检测及调用,就能进行拓展来将满足这些注解条件、条件的Bean加载到spring容器中。
此后我们来看下另一个重要的方法:this.deferredImportSelectorHandler.process();这里就是springBoot项目根据你引用的jar包就能自动帮你配置,不用你像以前springMVC那样手动的去写一些配置了。
在这个方法中进行debug:
可以看到
SpringFactoriesLoader.loadFactoryNames()方法,而这个spring.factories就是在每个jar包下面,所以你引用了什么jar包,就会帮你自动注入那些需要的类,然后可以看到加载了哪些Bean:
我们选两个典型来看下这些有什么用,WebMvcAutoConfiguration类:
看下其中的代码:
我们看到如果有类DispatcherServlet、WebMvcConfiguration,就进行加载。
DispatcherServletAutoConfiguration类
通过这些我们就知道了,DispathcherServlet中那些处理器、处理器适配器是通过什么注入进去的了,以及那些需要的Bean是怎样自动注入的。
自此。关于SpringBoot项目的启动就大体有所了解了。