目录

一、概观Spring Boot

二、Spring Boot应用初始化

2.1 初始化入口

2.2 SpringApplication的run方法

2.3 方法分析

三、容器创建与初始化

3.1 creatApplicationContext()方法

3.2 prepareContext(context, environment, listener, applicationArguments, printedBanner)方法

3.3 refreshContext(context)方法

四、总结

一、概观SpringBoot

随着分布式、微服务和云计算时代的到来,Spring Boot框架的重要性日益突显。Spring官方给出的Spring Boot框架的特性:

  • 可以创建独立的Spring应用
  • 直接内嵌Tomcat, Jetty 或者 Undertow,不再需要开发WAR类型文件
  • 提供各式的"starter"依赖,来简化项目的创建配置
  • 任何时候都尽可能地自动化配置Spring和第三方库
  • 提供犹如健康指标检测和外部配置的生产环境特性
  • 完全没有代码生成和不需要xml配置

从官方给出的特性来看,Spring Boot适合做分布式系统和云上应用的底层框架,内嵌容器不需要再安装配置容器,而且提供了很多已经配置好的第三方框架和应用,并且主张“约定大于配置”,即拿来即用,适合使用java config注解配置,让开发人员更关注与业务代码。所以,在这么多诱惑下,自己便决定研究一下Spring Boot框架的源码,从源码来了解Spring Boot的迷人之处。

二、Spring Boot应用初始化

Spring框架的IoC和AOP是其强大之处,而Spring框架下的应用都会使用这两种技术,所以使用该框架的开发人员都应该去了解ioc和aop技术。而Spring Boot是Spring框架的即用版,因此,从Spring Boot源码中学习IoC容器的创建初始化以及AOP技术应用的思想,是我认为比较便捷的方法。同时,还可以学习到Spring Boot在整合Spring和第三方框架及应用的思想和技巧。接下来,我将从Spring Boot应用的启动入口开始分析,逐步分析启动流程。

2.1 初始化入口

下面是Spring Boot应用最简单的启动代码:

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

从这段代码可以知道,应用的主方法main调用了SpringApplication.run()方法,开启了应用初始化。那么,接下来我们看看它是怎么初始化容器的。

2.2 SpringApplication的run方法

public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);}
try {
listeners.running(context);
}catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

2.3 方法分析

  • StopWatch类:计时类,计算SpringBoot应用的启动时间。
  • SpringBootExceptionReporter类:是一个回调接口,用于支持SpringApplication启动错误的自定义报告。
  • configureHeadlessProper()方法:配置Headless模式配置,该模式下系统缺少显示设备、鼠标或键盘,而服务器端往往需要在该模式下工作。
  • getRunListeners(args)方法:获取SpringApplicationRunListeners类,是SpringApplicationRunListener类的集合。
  • SpringApplicationRunListener类:SpringApplication的run方法的监听器。
  • DefaultApplicationArguments(args)类:提供访问运行一个SpringApplication的arguments的访问入口。
  • prepareEnvironment(listeners,applicationArguments)方法:创建和配置Environment,同时在调用AbstractEnvironment构造函数时生成PropertySourcesPropertyResolver类。
  • configureIgnoreBeanInfo(environment)方法:配置系统IgnoreBeanInfo属性。
  • printBanner(environment)方法:打印启动的图形,返回Banner接口实现类。
  • createApplicationContext()方法:根据SpringApplication构造方法生成的webApplicationType变量创建一个ApplicationContext,默认生成AnnotationConfigApplicationContext。
  • getSpringFactoriesInstances(SpringBootExceptionRepoter.class, new Class[] {ConfigurableApplicationContext.class }, context)方法:获取SpringBootExceptionReporter类的集合。
  • prepareContext(context, environment, listener, applicationArguments, printedBanner)方法:设置Environment,在ApplicationContext中应用所有相关的后处理,在刷新之前将所有的ApplicationContextInitializers应用于上下文,设置SpringApplicationRunLIstener接口实现类实现多路广播Spring事件,添加引导特定的单例(SpringApplicationArguments, Banner),创建DefaultListableBeanFactory工厂类,从主类中定位资源并将资源中的bean加载进入ApplicationContext中,向ApplicationContext中添加ApplicationListener接口实现类。
  • refreshContext(context)方法:调用AbstractApplicationContext的refresh()方法初始化DefaultListableBeanFactory工厂类。
  • afterRefresh(CongigurableApplicationContext context, ApplicationArguments args)方法:在刷新ApplicationContext之后调用,在SpringAppliation中是方法体为空的函数,故不做任何操作。
  • listeners.started(context)方法:在ApplicationContext已经刷新及启动后,但CommandLineRunners和ApplicationRunner还没有启动时,调用该方法向容器中发布SpringApplicationEvent类或者子类。
  • callRunners(context, applicationArguments)方法:调用应用中ApplicationRunner和CommanLineRunner的实现类,执行其run方法,调用时机是容器启动完成之后,可以用@Order注解来配置Runner的执行顺序,可以用来读取配置文件或连接数据库等操作。
  • listeners.running(context)方法:在容器刷新以及所有的Runner被调用之后,run方法完成执行之前调用该方法。调用之前得到的SpringApplicationRunListeners类running(context)方法。
  • 最后,向应用中返回一个之前获得到的ApplicationContext。

三、容器创建与初始化

  在第二部分的SpringApplication的run()方法中,我们已经大致了解到了Spring Boot应用在启动时做了哪些工作,与容器初始化相关的方法是createApplciationContext()、prepareContext(context, environment, listener, applicationArguments, printedBanner)以及refreshContext(context)。那这一部分将关注与Spring IoC容器的创建和初始化相关的SpringApplication方法。

3.1 creatApplicationContext()方法

  根据SpringApplication构造方法生成的webApplicationType变量创建一个ApplicationContext,默认生成AnnotationConfigApplicationContext。

(1)时序图

(2)方法的源码

protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}catch (ClassNotFoundException ex) {
throw new IllegalStateException("Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

(3)方法分析

  a. 方法根据applicationContextClass变量是否为空,决定是否执行下面的switch语句,而applicationContextClass变量是由SpringApplicationBuilder类中的contextClass()方法调用ApplicationContext的setApplicationContextClass()赋值的,默认为空;

  b. webApplicationType变量是SpringApplication.run()方法调用构造方法时赋值的;

  c. switch语句通过反射根据webApplicationType生成对应的容器,分别是AnnotationConfigServletWebServerApplicationContext、AnnotationConfigReactiveWebServerApplicationContext以及AnnotationConfigApplicationContext的,默认生成的是AnnotationConfigApplicationContext,同时,其构造函数生成AnnotedBeanDefinitonReader和ClassPathBeanDefinitionScanner类;

  d. 最后,通过BeanUtils工具类将获取到的容器类转换成ConfigurableApplicationContext类,返回给应用使用。

3.2 prepareContext(context, environment, listener, applicationArguments, printedBanner)方法

  prepareContext方法的作用是,设置Environment,在ApplicationContext中应用相关的后处理,在刷新之前将任何的ApplicationContextInitializers应用于上下文,设置SpringApplicationRunLIstener接口实现类实现多路广播Spring事件,添加引导特定的单例(SpringApplicationArguments, Banner),创建DefaultListableBeanFactory工厂类,从主类中定位资源并将资源中的bean加载进入ApplicationContext中,向ApplicationContext中添加ApplicationListener接口实现类。接下来,我们将从源码入手,逐步分析prepareContext()方法所做的工作。

(1)prepareContext()源码

private void prepareContext(ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}

(2)prepareContext时序图

(3)方法解析

  • context.setEnvironemnt(environment)方法:为容器设置环境,该Environment类是run()方法中的prepareEnvironment()方法获取的,默认为StandardEnvironment类。
  • postProcessApplicationContext(context)方法:在ApplicationContext中应用相关的后处理。

    a. 根据应用中的beanNameGernerator引用是否为空(默认为空),决定是否向容器中注入BeanNameGenerator类的实现类;

    b. 根据resourceLoader引用是否为空(默认为DefaultResourceLoader类,在printBanner()阶段获得)以及context的类型,决定配置resource的地方和方式,若context(默认为AnnotationConfigApplicationContext)为GenericApplicationContext类或子类,则向context中添加    resourceLoader,若context为DefaultResourceLoader类或子类,则向context中添加resourceLoader类的ClassLoader类实例;

    c. 根据addConversionService的布尔值(默认为true),决定是否向容器中添加ApplicationConversionServivce类实例。

  • applyInitializers(context)方法:在容器刷新之前,应用所有的ApplicationContextInitializer接口实现类。遍历执行getInitializers()方法得到的集合的initialize(context)方法初始化context容器,而for方法遍历的ApplicationContextInitializer集合是应用执行SpringApplication构造函数时getSpringFactoriesInstances()方法设置的。
  • listeners.contextPrepared(context)方法:遍历执行run方法里getRunListeners()得到的SpringApplicationRunListeners (SpringApplicationRunListener的集合)的contextPrepared(context)方法。执行时机是,ApplicationContext容器完成创建和准备之后,并且只调用一次。容器提供的SpringApplicationRunListener接口实现类是EventPublishingRunListener类,该类构造函数生成的SimpleApplciationEventMulticaster类用来多路广播发布SpringApplicationEvent接口的实现类。
  • logStartupInfo(context.getParent()==null)方法:记录启动信息,其子类可以覆盖该方法以添加附加信息。
  • logStartupProfileInfo(context)方法:记录活动配置文件信息。
  • context.getBeanFactory()方法:调用之前得到的ApplicationContext容器(默认AnnotationConfigApplicationContext)的getBeanFactory()得到一个BeanFactory接口实现类(默认DefaultListableBeanFactory类),转换为ConfigurableListableBeanFactory类。
  • beanFactory.registerSingleton("springApplicationArguments", applicationArguments)方法:往容器中注册ApplicationArguments接口实现类(默认DefaultApplicationArguments类)的单例。
  • beanFactory.registerSingleton("springBootBanner", printedBanner)方法:向容器中添加printBanner(environment)方法返回的Banner类的单例。
  • ((DefaultListableBeanFactory) beanfactory).setAllowBeanDefinitionOverring(this.allowBeanDefinitionOverriding)方法:设置BeanDefinitio覆盖的开关。
  • getAllSources()方法:获取到应用中所有的资源,即Bean的资源定位阶段。该资源获取的地点是,在SpringApplication构造方法中产生,将run(MyApplication.class,args)中的MyApplication.class转换存储到LinkedHashSet<>中,并返回一个该资源Set的引用primarySources,在getAllSource()方法中获取该primarySources。
  • Assert.notEmpty(sources, "Sources must not be empty")方法:断言,判断获取到的sources是否为空,为空则停止应用并返回错误信息。
  • load(context, sources.toArray(new Object[0]))方法:从上面获取的资源中加载bean进入ApplicationContext中,即bean的加载阶段。加载流程如下:

a.创建了BeanDefinitionLoader类,将传入的context容器类型转换为BeanDefinitionRegistry(该转换局部生效);

    b.创建了AnnotedBeanDefinitionReader类、AnnotationScopeMetadataResolver类、AnnotationBeanNameGenerator类以及ConditionEvaluator类;

    c.创建XmlBeanDefinitionReader类、SimpleSaxErrorHandler类、XmlValidationModeDetector类以及NameThreadLocal类;

    d. 创建了ClassPathBeanDefintionScannerl类以及GroovyBeanDefintionReader类(该类根据BeanDefinitionLoader中的isGroovyPresent()返回的布尔值决定是否创建);

    e. 配置得到的BeanDefinitionLoader,并调用其load()方法,开始加载BeanDefinition;

    f. 根据传入的资源的类型,决定加载Bean的方式以及BeanDefinition的类型(默认为AnnotatedGenericBeanDefinition类);

    g. 解析含有@Scope注解的BeanDefinition获得其ScopeMetadata,并将scope添加到获得的BeanDefinition中; h. 解析BeanDefinition获得beanName;

    i. 解析含有@Lazy注解的BeanDefinition,根据注解属性值决定是否执行setLazyInit()方法;

    j. 遍历函数输入参数BeanDefinitionCustomizer(该接口是功能性接口)的集合,执行其customizer(abd)方法;

    k. 将刚才得到的BeanDefinition和beanName添加到BeanDefinitionHolder中;

    l. 利用AOP框架创建作用域代理类,根据刚刚获得的ScopeMetadata的getScopedProxyMode()方法返回的值,ScopedProxyMode 决定是否生成代理类并决定使用jdk代理生成代理类还是cglib生成代理类,并将得到的proxyDefinition代替之前的BeanDefinition添加到BeanDefinitionHolder中;

    m. 向容器中注册别名aliases和beanName;

  • listeners.contextLoaded(context)方法:遍历执行之前获得的SpringApplicationRunListener接口实现类的contextLoaded(context)方法。

3.3 refreshContext(context)方法

  调用AbstractApplicationContext的refresh()方法初始化DefaultListableBeanFactory工厂类。

(1)refreshContext(context)源码

private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
}
}
}

  调用的AbstractApplicationContext.refresh()源码:

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
}
}
}

(2)refreshContext(context)时序图

  下面时refreshContext(context)实际刷新容器的AbstractApplicationContext.refresh()的时序图:

(3)方法分析

  • prepareRefresh()方法:为刷新准备好容器。

a. 设置启动时间;

b. 设置标示当前context是否活动的标签,active为true,closed为false,类型为AtomicBoolean;

c. 在context环境中初始化placeholder属性源,默认不做任何事情;

d. 验证所有标记required的property都是可解析的;

e. 创建ApplicationEvent的集合,即LinkedHashSet<ApplicationEvent>。一旦多路广播器可用(即prepareContext()阶段得到的SimpleApplicationEventMulticaster类),便允许发布早期的ApplicationEnvent的集合;

  • obtainFreshBeanFactory()方法:告诉子类刷新内部的bean工厂类。

a. 持有一个工厂类单例(默认为DefaultListableBeanFactory),并依靠调用者通过工厂类单例或构造方法注册bean;

b. 将在AbstarctApplicationContext类生成的id和在DefaultListableBeanFatory生成指向自身的弱引用,存储进入一个由DefaultListableBeanFactory持有的Map中。

  • prepareBeanFactory(beanFactory)方法:准备在context中要使用的beanFactory。配置工厂的标准context特性,比如容器的ClassLoader和后处理器。

a. 设置ClassLoader;

b. 设置BeanExpressionResolver接口实现类(为StandardBeanExpressionResolver类);

c. 设置PropertyEditorRegistrar接口实现类(为ResourceEditorRegistrar类);

e. 将ApplicationContextAwareProcessort添加进入应用获得的工厂类实例持有的CopyOnWriteArrayList的一个引用中;

f. 将EnvironmentAware.class、EmbeddedValueResolverAware.class、ResourceLoaderAware.class、ApplicationEventPublisherAware.class、MessageSourceAware.class、MessageSourceAware.class 添加进入应用获得的工厂类实例持有的HashSet的一个引用中;

g. 在普通工厂类中未注册成为可解析类型的工厂类接口,而MessageSource作为bean被注册(查找到并自动装配)。

h. 将BeanFactory.class、ResourceLoader.class、ApplicationEventPublisher.class、ApplicationContext.class 添加进入应用获得的工厂类实例持有的ConcurrentHashMap<Class<?>, Object>的一引用中;

i. 注册为了检测内部bean的早期后处理器,例如ApplicationListeners;

j. 将ApplicationListenerDetector的实例、LoadTimeWeaverAwareProcessor的实例添加进入应用获得的工厂类实例持有的CopyOnWriteArrayList<BeanPostProcessor>的一个引用中;

k. 为持有的工厂类设置临时可以匹配类型的ClassLoader,为ContextTypeMatchClassLoader类;

l. 配置默认的环境单例bean;

  • postProcessBeanFactory(beanFactory)方法:允许容器子类中的bean工厂执行后处理。该方法执行时机时,在ApplicationContext内部bean工厂类标准初始化之后修改它,这时所有的BeanDifinition已经被加载,但是还没有被实例化。继承这个方法允许某些AbstractApplicationContext类的子类中注册特殊的类似BeanPostProcessors的类。默认不做任何操作。
  • invokeBeanFactoryPostProcessors(beanFactory)方法:实例化所有已经注册的BeanFactoryPostProcessor的bean(实例化为单例),并遵循已给出的明确order值调用它,bean实例化与依赖注入开始阶段。

    a. 实际调用了PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessor(beanfactory, getBeanFactoryPostProcessor)方法,在这个方法里完成了实例化和调用任务;

c. 不实例化FactoryBean,并保留所有常规bean,不初始化它们,让之后的bean工厂后处理器应用他们;

d. 区分开实现了PriorityOrdered类的BeanDefinitionRegistryPostProcessor类,将其实例化并装入一个ArrayList的容器中;

e. 将刚刚获得的BeanDefinitionRegistryPostProcessor的集合根据order的值排序;

f. 遍历调用得到的BeanDefinitionRegistryPostProcessor类bean的postProcessBeanDefinitionBeanDefinitionRegistry(registry)方法;

g. 清除BeanDefinitionRegistryPostProcessor的ArrayList集合里的bean;

h. 区分开实现了Ordered类的BeanDefinitionRegistryPostProcessor类,将其实例化并装入一个ArrayList的容器中,并重复执行一次e到g的步骤;

i. 最后,调用所有其他的BeanDefinitionRegistryPostProcessor,直到不再出现其他的BeanDefinitionRegistryPostProcessor,也重复执行一次e到g的步骤;

j. 调用到目前为止的已处理的所有处理器的postProcessBeanFactory回调;

g. 调用context实例注册的factory的processor;

i. 清空缓存的合并的Bean定义,因为后处理器可能会修改原始的元数据,例如,替换值中的占位符。

  • registerBeanPostProcessors(beanFactory)方法:注册拦截bean创建的bean处理器。

a. 向context持有的bean factory注册BeanPostProcessorChecker,该检查器其用来记录在BeanPostProcessor实例化期间创建bean时的info信息,即当所有BeanPostProcessor都不对bean进行后处理操作时记录。

b. 将所有的BeanPostProcessor按照实现PriorityOrdered、Oedered和剩下的区别,分别添加进三个ArrayList容器;

c. 对刚刚获得ArrayList分别根据order值进行排序,最后整合后注册进入bean factory中;

d. 重新注册后处理器,用于检测像ApplicationListener的内部类,将其移动到后处理器链的末端,用于提取代理等作用;

  • initMessageSource()方法:为context初始化message源。从容器中获得MessageSource的bean,若没有定义,则会调用父类的MessageSource(无值,并会打印出没有message source的日志信息)。此例为单例。
  • initApplicationEventMulticaster()方法:实例化应用事件多路广播器ApplicationEventMulticaster。从容器中获取ApplicationEventMulticaster的bean,若没有注册,则注入SimpleApplicationEventMulticaster类的bean。
  • onRefresh()方法:该方法使模板方法,在特定的context子类中初始化其他特殊的bean。

a. 在GenericWebApplicationContext、StaticWebApplicationContext中,该方法初始化了context的ThemeSource;

b. 在ServletWebServerApplicationContext、ReactiveWebServerApplicationContext中,该方法初始化类context的TnemeSource并创建了一个ServerManager。

  • registerListeners()方法: 检测监听器并注册它们。向刚才获得的ApplicationEventMulticaster中注册实现了ApplicationListener的监听器bean,但不影响那一些可以不用生成bean就可以加载的监听器。
  • finishBeanFactoryInitialization(beanFactory)方法:实例化所有剩下的单例bean(没有执行lazy初始化)。

a. 初始化context的类型转换服务;

b. 如果之前没有任何注册的bean后处理器(比如,一个PropertyPlaceholderConfigurer的bean),则注册一个默认的内嵌的值解析器,在这一观点下,优先解析注解属性值;

c. 尽早初始化LoadTimeWeaverAwarebean,以便尽早注册它们的转换器;

d. 停止使用临时的类型匹配类加载器;

e. 允许缓存所有的bean定义元数据,不需要进一步修改了;

f. 实例化所有剩下的单例(没有Lazy初始化的bean);

  • finishRefresh()方法:发布相应的事件。

a. 清除context级别的资源缓存(例如,扫描得来的ASM元数据);

b. 为context初始化生命周期处理器;

c. 首先向生命周期处理器传播刷新;

d. 发布最后的事件(ContextRreshedEvent);

e. 若激活的话,便参与LiveBeansView类的mbean,。

  • destroyBeans()方法:摧毁已经创建的bean,避免悬空资源。
  • cancelRefresh(ex)方法:取消刷新,设置active变量为false。
  • resetCommonCaches()方法:重置Spring中的内省缓存,因为应用可能不再需要单例bean的元数据了。

a. 清除声明方法缓存,清除声明变量缓存(ConcurrentReferenceHashMap数据类型);

b. 清除注解相关缓存;

c. 清除可解析类型相关缓存;

d. 清除相关类加载器缓存(ConcurrentHashMap)。

四、总结

  到此为止,分析了Spring Boot应用启动过程run方法中,自己比较感兴趣的三个方法,再以此延伸又接触到了更多的相关类和相关方法,重新复习了许多java知识(继承、重载、重写、接口、反射以及设计模式)。虽然自己还没有能力写出这么优美的框架,但是从分析源码中自己学习到了不少的框架设计知识,接触到比较底层的设计思想。不尽人意的是,有些方法和重要类的分析由于自己能力有限,解释得还有些模糊,决定在接下来的文章里将这些遗憾弥补回来。欢迎指正!

SpringBoot框架——从SpringBoot看IoC容器初始化流程之方法分析的更多相关文章

  1. 【spring源码分析】IOC容器初始化(一)

    前言:spring主要就是对bean进行管理,因此IOC容器的初始化过程非常重要,搞清楚其原理不管在实际生产或面试过程中都十分的有用.在[spring源码分析]准备工作中已经搭建好spring的环境, ...

  2. Spring IoC容器初始化过程学习

    IoC容器是什么?IoC文英全称Inversion of Control,即控制反转,我么可以这么理解IoC容器: 把某些业务对象的的控制权交给一个平台或者框架来同一管理,这个同一管理的平台可以称为I ...

  3. Java开发工程师(Web方向) - 04.Spring框架 - 第2章.IoC容器

    第2章.IoC容器 IoC容器概述 abstract: 介绍IoC和bean的用处和使用 IoC容器处于整个Spring框架中比较核心的位置:Core Container: Beans, Core, ...

  4. spring源码学习之路---深度分析IOC容器初始化过程(四)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 最近由于工作和生活,学习耽搁 ...

  5. 挖坟之Spring.NET IOC容器初始化

    因查找ht项目中一个久未解决spring内部异常,翻了一段时间源码.以此文总结springIOC,容器初始化过程. 语言背景是C#.网上有一些基于java的spring源码分析文档,大而乱,乱而不全, ...

  6. IOC 容器初始化

    WebApi 插件式构建方案:IOC 容器初始化 一般来说,一个现代化的网站加载流程是这样的:程序集加载后,我们会初始化 IOC 容器,以便于接下来解析对象用. 我们插件式的开发,这一步更为重要.这是 ...

  7. 【spring源码分析】IOC容器初始化(二)

    前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...

  8. 【spring源码分析】IOC容器初始化(四)

    前言:在[spring源码分析]IOC容器初始化(三)中已经分析了BeanDefinition注册之前的一些准备工作,下面将进入BeanDefinition注册的核心流程. //DefaultBean ...

  9. 【spring源码分析】IOC容器初始化(十)

    前言:前文[spring源码分析]IOC容器初始化(九)中分析了AbstractAutowireCapableBeanFactory#createBeanInstance方法中通过工厂方法创建bean ...

随机推荐

  1. Word Flow:创造吉尼斯世界纪录的触屏文本输入的全新体验——微软Windows Phone 8.1系统倾情巨献

    Flow:创造吉尼斯世界纪录的触屏文本输入的全新体验--微软Windows Phone 8.1系统倾情巨献" title="Word Flow:创造吉尼斯世界纪录的触屏文本输入的全 ...

  2. 为什么前两年大热的VR创业突然冷了?

    不得不说,如果不是<头号玩家>在国内的热映,人们似乎都要忘记VR这个行业了.<头号玩家>中那些带有极强真实色彩的游戏,其实就是VR进化的目标,甚至是巅峰!而里面的角色佩戴的设备 ...

  3. 探索真实事物的虚拟再现——微软亚洲研究院SIGGRAPH Asia 2014精彩入选论文赏析

    Asia 2014精彩入选论文赏析" title="探索真实事物的虚拟再现--微软亚洲研究院SIGGRAPH Asia 2014精彩入选论文赏析"> SIGGRAP ...

  4. Spring Boot 学习笔记(六) 整合 RESTful 参数传递

    Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...

  5. string删除与查找erase,find

    s.erase( 指针位置 , 删除长度 ) 返回值修改后的string对象引用 find(string, int):第一个参数用来指示要查找的字符,第二个参数用来表示从字符串的何处开始查找子串(默认 ...

  6. keepalive笔记之一:基本安装

    在安装文件中有范例说明 /usr/share/doc/keepalived-1.2.13/samples/ Keepalived:它的诞生最初是为ipvs(一些服务,内核中的一些规则)提供高可用性的, ...

  7. 读书笔记之 数字图像处理的MATLAB实现(第2版)

  8. Ionic3学习笔记(十四)使用 videogular2 实现视频播放以及遇到的一些问题

    本文为原创文章,转载请标明出处 目录 使用 videogular2 安装 增加图标.字体支持 导入 module 举个例子 遇到的问题 iOS 端自动进入全屏播放 Android 端 autoplay ...

  9. Harbor快速搭建企业级Docker仓库

    Github: https://github.com/goharbor/harbor 改端口安装: https://www.cnblogs.com/huangjc/p/6420355.html 相关博 ...

  10. react和vue

    react整体的思路就是函数式,所以推崇纯组件,数据不可变,单向数据流,当然需要双向的地方也可以做到,比如结合redux-form,而vue是基于可变数据的,支持双向绑定.react组件的扩展一般是通 ...