書接上篇
該說refreshContext(context)了,首先是判斷context是否是AbstractApplicationContext派生類的實例,之后調用了強轉為AbstractApplicationContext類型並調用它的refresh方法。由於AnnotationConfigEmbeddedWebApplicationContext繼承自EmbeddedWebApplicationContext,所以會執行EmbeddedWebApplicationContext的refresh方法,繼而執行其中的super.refresh。這個refresh也就是AbstractApplicationContext的refresh方法了,它內部是一個synchronized鎖全局的代碼塊,同樣的加鎖方法還有這個類里的close和registerShutdownHook方法。
同步代碼塊中第一個方法prepareRefresh,首先會執行AnnotationConfigEmbeddedWebApplicationContext的prepareRefresh方法:
protected void prepareRefresh() { 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 void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(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(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(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:
@Override protected void postProcessBeanFactory(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 void invokeBeanFactoryPostProcessors(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(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }
BeanFactory后置處理器執行之后是注冊Bean的后置處理器方法registerBeanPostProcessors。例如new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)會在Bean沒有合適的后置處理器時記條info級日志。ApplicationListenerDetector也注冊了一個。
initMessageSource這個方法在我這沒什么用,都說是國際化的,隨便百度一下一堆一堆的,而且其實嚴格來說這篇多數不屬於spring boot的部分,這方法我就不細寫了。
initApplicationEventMulticaster方法主要也就是初始化並注冊applicationEventMulticaster的這兩句代碼:
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(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 void initServletPropertySources( 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) instanceof StubPropertySource) { propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, new ServletContextPropertySource(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) instanceof StubPropertySource) { propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig)); } }
registerListeners首先注冊靜態監聽:
@Override public 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 * {@link org.springframework.context.event.ContextRefreshedEvent}. */ protected void finishRefresh() { // 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 void registerApplicationContext(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(new LiveBeansView(), new ObjectName(mbeanDomain, MBEAN_APPLICATION_KEY, applicationName)); } catch (Throwable ex) { throw new ApplicationContextException("Failed to register LiveBeansView MBean", ex); } } applicationContexts.add(applicationContext); } } }
finishRefresh最后會啟動前面創建的內嵌容器,並發布EmbeddedServletContainerInitializedEvent事件,啟動這一部分算是容器的邏輯了,有機會整理容器邏輯再細寫,我這里是Tomcat的:
@Override public void start() throws EmbeddedServletContainerException { 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(); throw ex; } catch (Exception ex) { throw new EmbeddedServletContainerException( "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 {@link ReflectionUtils}, * {@link ResolvableType} and {@link CachedIntrospectionResults} caches. * @since 4.2 * @see ReflectionUtils#clearCache() * @see ResolvableType#clearCache() * @see CachedIntrospectionResults#clearClassLoader(ClassLoader) */ protected void resetCommonCaches() { 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 {@code doClose()} for the actual closing procedure. * @see Runtime#addShutdownHook * @see #close() * @see #doClose() */ @Override public void registerShutdownHook() { if (this.shutdownHook == null) { // No shutdown hook registered yet. this.shutdownHook = new Thread() { @Override public void run() { synchronized (startupShutdownMonitor) { doClose(); } } }; Runtime.getRuntime().addShutdownHook(this.shutdownHook); } }
==========================================================
咱最近用的github:https://github.com/saaavsaaa
微信公眾號: