Spring中refresh分析之onRefresh方法详解

关联博文:
AbstractApplicationContext中refresh方法详解
Spring中refresh分析之prepareRefresh方法详解
Spring中refresh分析之obtainFreshBeanFactory方法详解
Spring中refresh分析之prepareBeanFactory方法详解
Spring中refresh分析之postProcessBeanFactory方法详解
Spring中refresh分析之invokeBeanFactoryPostProcessors方法详解
Spring中refresh分析之registerBeanPostProcessors方法详解
Spring中refresh分析之initMessageSource方法详解
Spring中refresh分析之initApplicationEventMulticaster方法详解
Spring中refresh分析之onRefresh方法详解
Spring中refresh分析之registerListeners方法详解
Spring中refresh分析之finishBeanFactoryInitialization方法详解
Spring中refresh分析之finishRefresh方法详解

接上文Spring中refresh分析之initApplicationEventMulticaster方法详解我们分析过initApplicationEventMulticaster后,本文分析onRefresh方法。

首先调用父类的方法初始化主题源(themeSource)然后创建并启动WebServer。SpringBoot内置的Tomcat或者UndertowWebServer就是在这里实例化的。

【1】方法概览

ServletWebServerApplicationContext的onRefresh如下所示:

@Override
protected void onRefresh() {
	super.onRefresh();
	try {
		createWebServer();
	}
	catch (Throwable ex) {
		throw new ApplicationContextException("Unable to start web server", ex);
	}
}

父类GenericWebApplicationContext的onRefresh如下所示,只是初始化了ThemeSource。

//GenericWebApplicationContext
@Override
protected void onRefresh() {
	this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}

【2】initThemeSource

抽象类UiApplicationContextUtils 其实只做了一件事,即实例化ThemeSource 。

public abstract class UiApplicationContextUtils {
	public static final String THEME_SOURCE_BEAN_NAME = "themeSource";
	private static final Log logger = LogFactory.getLog(UiApplicationContextUtils.class);


	 //检测是否存在themeSource,如果不存在则创建一个空的ThemeSource 
	public static ThemeSource initThemeSource(ApplicationContext context) {
		if (context.containsLocalBean(THEME_SOURCE_BEAN_NAME)) {
			ThemeSource themeSource = context.getBean(THEME_SOURCE_BEAN_NAME, ThemeSource.class);
			// Make ThemeSource aware of parent ThemeSource.
			if (context.getParent() instanceof ThemeSource && themeSource instanceof HierarchicalThemeSource) {
				HierarchicalThemeSource hts = (HierarchicalThemeSource) themeSource;
				if (hts.getParentThemeSource() == null) {
					// Only set parent context as parent ThemeSource if no parent ThemeSource
					// registered already.
					hts.setParentThemeSource((ThemeSource) context.getParent());
				}
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Using ThemeSource [" + themeSource + "]");
			}
			return themeSource;
		}
		else {
			// Use default ThemeSource to be able to accept getTheme calls, either
			// delegating to parent context's default or to local ResourceBundleThemeSource.
			HierarchicalThemeSource themeSource = null;
			if (context.getParent() instanceof ThemeSource) {
				themeSource = new DelegatingThemeSource();
				themeSource.setParentThemeSource((ThemeSource) context.getParent());
			}
			else {
				themeSource = new ResourceBundleThemeSource();
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate ThemeSource with name '" + THEME_SOURCE_BEAN_NAME +
						"': using default [" + themeSource + "]");
			}
			return themeSource;
		}
	}

}

方法逻辑梳理如下:

  • 尝试从容器中获取themeSource,如果存在则尝试为其设置ParentThemeSource;
  • 如果容器中不存在themeSource则对parent进行判断:
    • 如果parent不为null且是ThemeSource,则实例化DelegatingThemeSource并设置parent;
    • 否则只是实例化ResourceBundleThemeSource;

本文这里只是实例化了ResourceBundleThemeSource。

【3】createWebServer

ServletWebServerApplicationContext的createWebServer方法如下所示。

private void createWebServer() {
	// 默认是null
	WebServer webServer = this.webServer;
	//本文这里servletContext 也是null
	ServletContext servletContext = getServletContext();
	if (webServer == null && servletContext == null) {
		ServletWebServerFactory factory = getWebServerFactory();
		this.webServer = factory.getWebServer(getSelfInitializer());
	}
	else if (servletContext != null) {
		try {
		// 如果servletContext 不为null,表示已经存在则启动
			getSelfInitializer().onStartup(servletContext);
		}
		catch (ServletException ex) {
			throw new ApplicationContextException("Cannot initialize servlet context", ex);
		}
	}
	// prepareRefresh中我们看到过,这里又出现了
	initPropertySources();
}

ServletWebServerApplicationContextgetWebServerFactory方法如下所示,根据ServletWebServerFactory.class从容器检索得到beanNames。本文这里得到的是tomcatServletWebServerFactory,然后从容器中获取TomcatServletWebServerFactory bean实例。

protected ServletWebServerFactory getWebServerFactory() {
	// Use bean names so that we don't consider the hierarchy
	// 本文这里拿到的是tomcatServletWebServerFactory
	String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
	if (beanNames.length == 0) {
		throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
				+ "ServletWebServerFactory bean.");
	}
	if (beanNames.length > 1) {
		throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
				+ "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
	}
	return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}

得到TomcatServletWebServerFactory 实例后就会进行后续WebServer的实例化流程。本文这里暂不深入分析,将另起章节学习可以参考SpringBoot中是如何创建WebServer的。之后我们在控制台可以看到如下日志打印:

在这里插入图片描述

我们继续往下看,将触发initPropertySources。


initPropertySources

在前面prepareRefresh方法中我们看到过这个方法,这里又出现了。
在这里插入图片描述

// GenericWebApplicationContext
@Override
protected void initPropertySources() {
	ConfigurableEnvironment env = getEnvironment();
	if (env instanceof ConfigurableWebEnvironment) {
		((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
	}
}

//StandardServletEnvironment
@Override
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
	WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
}

//WebApplicationContextUtils
public static void initServletPropertySources(MutablePropertySources sources,
		@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {

	Assert.notNull(sources, "'propertySources' must not be null");
	//servletContextInitParams
	String name = StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME;
	if (servletContext != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
		sources.replace(name, new ServletContextPropertySource(name, servletContext));
	}
	//servletConfigInitParams
	name = StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME;
	if (servletConfig != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
		sources.replace(name, new ServletConfigPropertySource(name, servletConfig));
	}
}

与前者不同的是,这里servletContext不为null(servletConfig 为null)。故而这里将替换sources中的servletContextInitParams值,更新为new ServletContextPropertySource(name, servletContext)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值