Spring Boot启动过程(二)
书接上篇
该说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启动过程(二)相关推荐
- Spring Boot启动过程(七):Connector初始化
Connector实例的创建已经在Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动中提到了: Connector是LifecycleMBeanBase的子类,先是设置L ...
- [Spring Boot] 2. Spring Boot 启动过程定制化
在上一篇文章中,从源码角度介绍了Spring Boot的启动过程.启动的代码虽然只有短短的一行,但是背后所做的工作还真不少,其中有一些可以定制化的部分,主要分为以下几个方面: 初始化器(Initial ...
- Spring Boot启动过程中相关事件
Spring容器创建前: ApplicationStartingEvent: Spring容器创建前,项目启动时执行; ApplicationEnvironmentPreparedEvent: Spr ...
- Spring boot 启动过程
先Mark, https://www.cnblogs.com/trgl/p/7353782.html https://blog.csdn.net/zl1zl2zl3/article/details/7 ...
- 强大的Spring Boot启动监听器事件-初始化系统账号密码
文章目录 前言 一.SpringApplicationEvents 事件类型 1.1 ApplicationStartingEvent 1.2 ApplicationEnvironmentPrepar ...
- Spring Boot 启动事件顺序
大家都知道,在 Spring 框架中事件和监听无处不在,打通了 Spring 框架的任督二脉,事件和监听也是 Spring 框架必学的核心知识之一. 一般来说,我们很少会使用到应用程序事件,但我们也不 ...
- Spring Boot 启动事件和监听器,太强大了!
大家都知道,在 Spring 框架中事件和监听无处不在,打通了 Spring 框架的任督二脉,事件和监听也是 Spring 框架必学的核心知识之一. 一般来说,我们很少会使用到应用程序事件,但我们也不 ...
- Spring Boot启动过程源码分析--转
https://blog.csdn.net/dm_vincent/article/details/76735888 关于Spring Boot,已经有很多介绍其如何使用的文章了,本文从源代码(基于Sp ...
- Spring Boot:(二)启动原理解析
Spring Boot:(二)启动原理解析 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏. ...
最新文章
- 反函数的导数:理论与应用
- 根据多个点使用canvas贝赛尔曲线画一条平滑的曲线
- RHEL5下源码配置LAMP全记录
- 配置服务器文件,服务器配置文件
- IDEA启动项目报错:非法字符: ‘\ufeff‘
- 20154322 杨钦涵 Exp2 后门原理与实践
- c++ 显示三维散点图_Matplotlib中的三维绘图
- js系列之每天一练成长录之一
- html验证码谷歌浏览器不显示,网页不显示验证码是怎么回事?
- java dto 生成_java – 从多个源DTO映射到一个目标
- 二维码签到,签退和登陆
- 语法糖(Syntactic sugar)
- Python爬虫实战—vmgrils图片网站
- PV-RCNN: Point-Voxel Feature Set Abstraction for 3D Object Detection(group的是关键点周围的体素,而不是周围的点)
- 如何成为“头脑王者”?每天5分钟,让你的大脑准备就绪!
- 路由器自身拥有IP地址吗?
- 数论——唯一分解定理
- Angr 操作栈的符号执行 04_angr_symbolic_stack
- 东距(easting)、北距(northing)、东伪偏移(false easting)、北伪偏移(false northing)
- 经典python项目源码_建议收藏,22个Python迷你项目(附源码)
热门文章
- 软件破解系列之OD中断方法
- 条款22: 尽量用“传引用”而不用“传值”
- 在页面中控制媒体流的起播点和播放长度
- android 无法接收广播_别告诉我你不认识Android中广播接收者(二)
- linux用户在哪个文件夹,LINUX中用命令成功建立一个用户后信息会记录在哪个文件中...
- PAT(甲级)2018年秋季考试 7-1 Werewolf - Simple Version
- PAT(甲级)2019年秋季考试 7-2 Merging Linked Lists
- Java入门培训班怎么选择
- 零基础可以学好UI设计吗
- java程序猿必读的学习书籍,良心推荐!