书接上篇

  该说refreshContext(context)了,首先是判断context是否是AbstractApplicationContext派生类的实例,之后调用了强转为AbstractApplicationContext类型并调用它的refresh方法。由于AnnotationConfigEmbeddedWebApplicationContext继承自EmbeddedWebApplicationContext,所以会执行EmbeddedWebApplicationContext的refresh方法,继而执行其中的super.refresh。这个refresh也就是AbstractApplicationContext的refresh方法了,它内部是一个synchronized锁全局的代码块,同样的加锁方法还有这个类里的close和registerShutdownHook方法。

  同步代码块中第一个方法prepareRefresh,首先会执行AnnotationConfigEmbeddedWebApplicationContext的prepareRefresh方法:

    protected voidprepareRefresh() {this.scanner.clearCache();super.prepareRefresh();}

  这个super也就是AbstractApplicationContext,它的prepareRefresh方法逻辑是:生成启动时间;设置closed状态为false;active状态为true;initPropertySources方法主要是调用了AbstractEnvironment的getPropertySources方法获取了之前SpringApplication的prepareEnvironment方法中getOrCreateEnvironment方法准备的各种环境变量及配置并用于初始化ServletPropertySources。具体的servletContextInitParams这些是在环境对象初始化时由各集成级别Environment的customizePropertySources方法中初始化的。

  接着的getEnvironment().validateRequiredProperties()方法实际执行了AbstractEnvironment中的this.propertyResolver.validateRequiredProperties(),主要是验证了被占位的key如果是required的值不能为null。prepareRefresh的最后是初始化this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>()。*****

  只够是获取BeanFactory实例的方法obtainFreshBeanFactory(),首先在refreshBeanFactory方法中用原子布尔类型判断是否刷新过,BeanFactory实例是在createApplicationContext创建Context实例时被创建的,如果没有刷新则设置一个用于序列化的id,id是ContextIdApplicationContextInitializer初始化设置的(如未配置该初始化器,是有一个默认ObjectUtils.identityToString(this)生成的),这个id的生成规则是spring.config.name截取的+":"+server.port的占位截取。设置序列化id时,同时保存了一个id和弱引用DefaultListableBeanFactory实例映射。

  得到了beanFactory后就是prepareBeanFactory(beanFactory)了,逻辑是注册了BeanClassLoader用于注入的bean实例的创建;StandardBeanExpressionResolver用于EL表达式,比如配置文件或者@Value("#{...}")等使用;用ResourceEditorRegistrar注册属性转换器,比如xml配置的bean属性都是用的字符串配置的要转成真正的属性类型;addBeanPostProcessor(new ApplicationContextAwareProcessor(this))注册ApplicationContextAwareProcessor,它的invokeAwareInterfaces方法会对实现指定接口的bean调用指定的set方法;ignoreDependencyInterface忽略对这些接口的自动装配,比如Aware这些是要做独立处理的,不适合通用的方法;然后是有几个类型直接手动注册,比如BeanFactory,这个很好理解;接着注册一个后置处理器ApplicationListenerDetector的实例,addBeanPostProcessor注册的会按照注册先后顺序执行;这个方法的最后判断了特定的4个bean名字,如果存在会做相应注册,包括loadTimeWeaver、environment、systemProperties和systemEnvironment。补充一点,在最开始创建实例的时候还执行过ignoreDependencyInterface(BeanNameAware.class);ignoreDependencyInterface(BeanFactoryAware.class);ignoreDependencyInterface(BeanClassLoaderAware.class)。

    protected voidprepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {//Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());beanFactory.setBeanExpressionResolver(newStandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));//Configure the bean factory with context callbacks.beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);//BeanFactory interface not registered as resolvable type in a plain factory.//MessageSource registered (and found for autowiring) as a bean.beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);//Register early post-processor for detecting inner beans as ApplicationListeners.beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));//Detect a LoadTimeWeaver and prepare for weaving, if found.if(beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(newLoadTimeWeaverAwareProcessor(beanFactory));//Set a temporary ClassLoader for type matching.beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}//Register default environment beans.if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());}if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());}if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());}}

  之后到了refresh的postProcessBeanFactory方法,首先是会走到AnnotationConfigEmbeddedWebApplicationContext的Override,需要注意的一点是,这是web环境,如果不是是不会加载这个上下文的,也就不会这么走。它重写的第一步是先走super也就是EmbeddedWebApplicationContext的postProcessBeanFactory,这里又注册了个后置处理器WebApplicationContextServletContextAwareProcessor的实例,构造参数是this,也就是当前上下文,同时忽略ServletContextAware接口,这个接口是用于获取ServletContext的,为什么要忽略呢,我猜应该是因为我们既然有了web应用并且内嵌servlet的上下文实例,还要ServletContext的实现就没什么用了,还有可能出现冲突的问题,有空我再确认下。然后是配置的basePackages和annotatedClasses:

@Overrideprotected voidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.postProcessBeanFactory(beanFactory);if (this.basePackages != null && this.basePackages.length > 0) {this.scanner.scan(this.basePackages);}if (this.annotatedClasses != null && this.annotatedClasses.length > 0) {this.reader.register(this.annotatedClasses);}}

  到了invokeBeanFactoryPostProcessors方法,这个方法就是执行之前注册的BeanFactory后置处理器的地方。代码一目了然,PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors中只是有些排序的逻辑,我就不说了:

    /*** Instantiate and invoke all registered BeanFactoryPostProcessor beans,* respecting explicit order if given.* <p>Must be called before singleton instantiation.*/protected voidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());//Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime//(e.g. through an @Bean method registered by ConfigurationClassPostProcessor)if (beanFactory.getTempClassLoader() == null &&beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(newLoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}

  BeanFactory后置处理器执行之后是注册Bean的后置处理器方法registerBeanPostProcessors。例如new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)会在Bean没有合适的后置处理器时记条info级日志。ApplicationListenerDetector也注册了一个。

  initMessageSource这个方法在我这没什么用,都说是国际化的,随便百度一下一堆一堆的,而且其实严格来说这篇多数不属于spring boot的部分,这方法我就不细写了。

  initApplicationEventMulticaster方法主要也就是初始化并注册applicationEventMulticaster的这两句代码:

            this.applicationEventMulticaster = newSimpleApplicationEventMulticaster(beanFactory);beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,this.applicationEventMulticaster);

  onRefresh也是根据环境不同加载的上下文不同而不同的,用于支持子类扩展出来的上下文特定的逻辑的。EmbeddedWebApplicationContext的onRefresh首先依然是super.onRefresh,逻辑就是初始化了主题;createEmbeddedServletContainer方法名我就不翻译了,一般情况下是使用getBeanFactory .getBeanNamesForType方法找到EmbeddedServletContainerFactory类型的实例,这也就是我之前那个问题解决过程中,为什么只要排除掉tomcat引用,引入jetty引用就可以自动换成jetty的原因。创建容器的过程中初始化方法selfInitialize注册了filter和MappingForUrlPatterns等,代码在AbstractFilterRegistrationBean等onStartup,这里就不细说了,如果能抽出时间说说之前查问题的时候查的容器代码再说。然后初始化PropertySources,servletContextInitParams和servletConfigInitParams:

    public static voidinitServletPropertySources(MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) {Assert.notNull(propertySources,"'propertySources' must not be null");if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME)instanceofStubPropertySource) {propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,newServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));}if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME)instanceofStubPropertySource) {propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,newServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));}}

  registerListeners首先注册静态监听:

@Overridepublic void addApplicationListener(ApplicationListener<?>listener) {synchronized (this.retrievalMutex) {this.defaultRetriever.applicationListeners.add(listener);this.retrieverCache.clear();}}

  接着是:

  registerListeners的最后,初始化过的earlyApplicationEvents如果有事件,这时候会被发布。

  finishBeanFactoryInitialization结束BeanFactory的初始化并初始化所有非延迟加载的单例。事实上我们自定义的单例Bean都是在这里getBean方法初始化的,所以如果注册的Bean特别多的话,这个过程就是启动过程中最慢的。初始化开始前先设置configurationFrozen为true,并this.frozenBeanDefinitionNames = StringUtils.toStringArray ( this. beanDefinitionNames )。如果有bean实例实现了SmartInitializingSingleton会有后置处理触发,不包括延迟加载的。例如:org.springframework.context.event. internalEventListenerProcessor会触发EventListenerMethodProcessor的afterSingletonsInstantiated方法对所有对象(Object的子类)处理。

  finishRefresh:Refresh的最后一步,发布相应事件。同样先执行EmbeddedWebApplicationContext中对应方法的super(EmbeddedWebApplicationContext)的对应方法:

    /*** Finish the refresh of this context, invoking the LifecycleProcessor's* onRefresh() method and publishing the* {@linkorg.springframework.context.event.ContextRefreshedEvent}.*/protected voidfinishRefresh() {//Initialize lifecycle processor for this context.
initLifecycleProcessor();//Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();//Publish the final event.publishEvent(new ContextRefreshedEvent(this));//Participate in LiveBeansView MBean, if active.LiveBeansView.registerApplicationContext(this);}

  初始化生命周期处理器,逻辑是判断beanFactory中是否已经注册了lifecycleProcessor,没有就new一个DefaultLifecycleProcessor并setBeanFactory(beanFactory),然后将它赋值给私有LifecycleProcessor类型的this变量。然后执行生命周期处理器的onRefresh,其中先startBeans,被start的beans是通过getBeanNamesForType(Lifecycle.class, false, false)从beanFactory中取出来的,例如endpointMBeanExporter和lifecycleProcessor,会去调用bean的start方法,endpointMBeanExporter的start中执行 locateAndRegisterEndpoints方法并设置running属性为true,这个过程加了ReentrantLock锁。bean都启动完会设置处理器的running为true。刷新完会发布ContextRefreshedEvent事件,这个事件除了都有的记录时间还执行了ConfigurationPropertiesBindingPostProcessor的freeLocalValidator方法,我这的逻辑是实际上执行了ValidatorFactoryImpl的close方法。这个逻辑的最后会检查一个配置spring.liveBeansView.mbeanDomain是否存在,有就会创建一个MBeanServer:

    static voidregisterApplicationContext(ConfigurableApplicationContext applicationContext) {String mbeanDomain=applicationContext.getEnvironment().getProperty(MBEAN_DOMAIN_PROPERTY_NAME);if (mbeanDomain != null) {synchronized(applicationContexts) {if(applicationContexts.isEmpty()) {try{MBeanServer server=ManagementFactory.getPlatformMBeanServer();applicationName=applicationContext.getApplicationName();server.registerMBean(newLiveBeansView(),newObjectName(mbeanDomain, MBEAN_APPLICATION_KEY, applicationName));}catch(Throwable ex) {throw new ApplicationContextException("Failed to register LiveBeansView MBean", ex);}}applicationContexts.add(applicationContext);}}}

  finishRefresh最后会启动前面创建的内嵌容器,并发布EmbeddedServletContainerInitializedEvent事件,启动这一部分算是容器的逻辑了,有机会整理容器逻辑再细写,我这里是Tomcat的:

@Overridepublic void start() throwsEmbeddedServletContainerException {try{addPreviouslyRemovedConnectors();Connector connector= this.tomcat.getConnector();if (connector != null && this.autoStart) {startConnector(connector);}checkThatConnectorsHaveStarted();TomcatEmbeddedServletContainer.logger.info("Tomcat started on port(s): " + getPortsDescription(true));}catch(ConnectorStartFailedException ex) {stopSilently();throwex;}catch(Exception ex) {throw newEmbeddedServletContainerException("Unable to start embedded Tomcat servlet container", ex);}finally{Context context=findContext();ContextBindings.unbindClassLoader(context, getNamingToken(context),getClass().getClassLoader());}}

  然后是resetCommonCaches:

    /*** Reset Spring's common core caches, in particular the {@linkReflectionUtils},* {@linkResolvableType} and {@linkCachedIntrospectionResults} caches.*@since4.2*@seeReflectionUtils#clearCache()*@seeResolvableType#clearCache()*@seeCachedIntrospectionResults#clearClassLoader(ClassLoader)*/protected voidresetCommonCaches() {ReflectionUtils.clearCache();ResolvableType.clearCache();CachedIntrospectionResults.clearClassLoader(getClassLoader());}

  refreshContext的最后是注册shutdown的钩子:

        if (this.registerShutdownHook) {try{context.registerShutdownHook();}catch(AccessControlException ex) {//Not allowed in some environments.
}}/*** Register a shutdown hook with the JVM runtime, closing this context* on JVM shutdown unless it has already been closed at that time.* <p>Delegates to {@codedoClose()} for the actual closing procedure.*@seeRuntime#addShutdownHook*@see#close()*@see#doClose()*/@Overridepublic voidregisterShutdownHook() {if (this.shutdownHook == null) {//No shutdown hook registered yet.this.shutdownHook = newThread() {@Overridepublic voidrun() {synchronized(startupShutdownMonitor) {doClose();}}};Runtime.getRuntime().addShutdownHook(this.shutdownHook);}}

==========================================================

咱最近用的github:https://github.com/saaavsaaa

微信公众号:

                      

转载于:https://www.cnblogs.com/saaav/p/6292524.html

Spring Boot启动过程(二)相关推荐

  1. Spring Boot启动过程(七):Connector初始化

    Connector实例的创建已经在Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动中提到了: Connector是LifecycleMBeanBase的子类,先是设置L ...

  2. [Spring Boot] 2. Spring Boot 启动过程定制化

    在上一篇文章中,从源码角度介绍了Spring Boot的启动过程.启动的代码虽然只有短短的一行,但是背后所做的工作还真不少,其中有一些可以定制化的部分,主要分为以下几个方面: 初始化器(Initial ...

  3. Spring Boot启动过程中相关事件

    Spring容器创建前: ApplicationStartingEvent: Spring容器创建前,项目启动时执行; ApplicationEnvironmentPreparedEvent: Spr ...

  4. Spring boot 启动过程

    先Mark, https://www.cnblogs.com/trgl/p/7353782.html https://blog.csdn.net/zl1zl2zl3/article/details/7 ...

  5. 强大的Spring Boot启动监听器事件-初始化系统账号密码

    文章目录 前言 一.SpringApplicationEvents 事件类型 1.1 ApplicationStartingEvent 1.2 ApplicationEnvironmentPrepar ...

  6. Spring Boot 启动事件顺序

    大家都知道,在 Spring 框架中事件和监听无处不在,打通了 Spring 框架的任督二脉,事件和监听也是 Spring 框架必学的核心知识之一. 一般来说,我们很少会使用到应用程序事件,但我们也不 ...

  7. Spring Boot 启动事件和监听器,太强大了!

    大家都知道,在 Spring 框架中事件和监听无处不在,打通了 Spring 框架的任督二脉,事件和监听也是 Spring 框架必学的核心知识之一. 一般来说,我们很少会使用到应用程序事件,但我们也不 ...

  8. Spring Boot启动过程源码分析--转

    https://blog.csdn.net/dm_vincent/article/details/76735888 关于Spring Boot,已经有很多介绍其如何使用的文章了,本文从源代码(基于Sp ...

  9. Spring Boot:(二)启动原理解析

    Spring Boot:(二)启动原理解析 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏. ...

最新文章

  1. 反函数的导数:理论与应用
  2. 根据多个点使用canvas贝赛尔曲线画一条平滑的曲线
  3. RHEL5下源码配置LAMP全记录
  4. 配置服务器文件,服务器配置文件
  5. IDEA启动项目报错:非法字符: ‘\ufeff‘
  6. 20154322 杨钦涵 Exp2 后门原理与实践
  7. c++ 显示三维散点图_Matplotlib中的三维绘图
  8. js系列之每天一练成长录之一
  9. html验证码谷歌浏览器不显示,网页不显示验证码是怎么回事?
  10. java dto 生成_java – 从多个源DTO映射到一个目标
  11. 二维码签到,签退和登陆
  12. 语法糖(Syntactic sugar)
  13. Python爬虫实战—vmgrils图片网站
  14. PV-RCNN: Point-Voxel Feature Set Abstraction for 3D Object Detection(group的是关键点周围的体素,而不是周围的点)
  15. 如何成为“头脑王者”?每天5分钟,让你的大脑准备就绪!
  16. 路由器自身拥有IP地址吗?
  17. 数论——唯一分解定理
  18. Angr 操作栈的符号执行 04_angr_symbolic_stack
  19. 东距(easting)、北距(northing)、东伪偏移(false easting)、北伪偏移(false northing)
  20. 经典python项目源码_建议收藏,22个Python迷你项目(附源码)

热门文章

  1. 软件破解系列之OD中断方法
  2. 条款22: 尽量用“传引用”而不用“传值”
  3. 在页面中控制媒体流的起播点和播放长度
  4. android 无法接收广播_别告诉我你不认识Android中广播接收者(二)
  5. linux用户在哪个文件夹,LINUX中用命令成功建立一个用户后信息会记录在哪个文件中...
  6. PAT(甲级)2018年秋季考试 7-1 Werewolf - Simple Version
  7. PAT(甲级)2019年秋季考试 7-2 Merging Linked Lists
  8. Java入门培训班怎么选择
  9. 零基础可以学好UI设计吗
  10. java程序猿必读的学习书籍,良心推荐!