4

Spring源码之六-onRefresh()方法

 2 years ago
source link: https://blog.51cto.com/u_15476035/5072054
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Spring源码之六-onRefresh()方法

原创

程序员田同学 2022-03-04 10:49:56 博主文章分类:spring ©著作权

文章标签 tomcat spring 模板方法 文章分类 Java 编程语言 阅读数1808

Spring源码之六-onRefresh()方法

大家好,我是程序员田同学。

今天带大家解读Spirng源码之六的onRefresh()方法,这是refresh()的其中的一个方法,看似是一个空方法,实则他是非常非常重要的,对于提高Spring的扩展性。

老规矩,先贴上Spring的核心方法refresh()方法的源码,以便读者可以丝滑入戏。

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			//1、刷新前的准备
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			//2、将会初始化 BeanFactory、加载 Bean、注册 Bean
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			//3、设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
			prepareBeanFactory(beanFactory);

			try {
				//4、模板方法
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//执行BeanFactory后置处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// 5、Register bean processors that intercept bean creation.
				//注册bean后置处理器
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				//国际化
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				//6、模板方法--springboot实现了这个方法
				onRefresh();

				// Check for listener beans and register them.
				//7、注册监听器
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				//8、完成bean工厂的初始化**方法**********************************************
				finishBeanFactoryInitialization(beanFactory);

				//9、 Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}
onRefresh()是模板方法,具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)

这是onRefresh()的主要作用,那么文章到这里就结束了,感谢阅读!

开玩笑,只说作用不举例那和耍流氓没有什么区别,接下来就以Spirng的典型实现Springboot来举例。

该方法的执行时机是Spring已经加载好了一些特殊的bean(内置的一些bean,实现了bean工厂后置处理器的类)之后,在实例化单例bean之前。让我们来看Springboot是怎么调用这个模板方法的。

一路的点击Springboot的核心入口run()方法,一路找到了我们今天的主角,Spring的refresh()方法中的onRefresh()方法。

点击查看Springboot的onRresh()的实现方法。

有两个包路径含有boot的,一定就是Spirngboot的实现方法。

Spring源码之六-onRefresh()方法_spring

这是Spirng的onRresh()的实现方法。

Spring源码之六-onRefresh()方法_tomcat_02

比对一下Spirng的onRresh()和SpirngbootRefersh的实现类对比,Springboot多了两个实现类,ReactiveWebServerApplicationContext类和ServletWebServerApplicationContext类。

我们分别查看这两个实现的onRresh()方法都做了什么?

方法名都是createWebServer()方法,以为这两个方法都是一个方法,仔细一看发现并不是。

Spring源码之六-onRefresh()方法_tomcat_03

两个createWebServer()方法做了什么呢?我们debug进去搂一眼。

ReactiveWebServerApplicationContext类的onRresh()方法并没有执行到,见名知意应该是跟webServer管理相关的,限于篇幅问题,留个坑暂时放在吧。

Spring源码之六-onRefresh()方法_模板方法_04

ServletWebServerApplicationContext类的onRefresh()方法执行到了,我们进去一探究竟。

	private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		//第一次进来webServer servletContext都是null,会进到if分支里面
		if (webServer == null && servletContext == null) {
			//这里就会来查找ServletWebServerFactory,也就是web容器的工厂,具体看下getWebServerFactory()方法,
			// 还是ServletWebServerApplicationContext这个类的方法
			//创建了 TomcatServletWebServerFactory 类
			ServletWebServerFactory factory = getWebServerFactory();
			//创建 Tomcat
			this.webServer = factory.getWebServer(getSelfInitializer());
		}
		else if (servletContext != null) {
			try {
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			}
		}
		initPropertySources();
	}

核心应该是 factory.getWebServer(getSelfInitializer()),这个方法是创建了一个容器。都有哪些容器呢?

Spring源码之六-onRefresh()方法_tomcat_05

我们看一下他的实现类有Jetty*、Mock*、Tomcat*,Tomcat就不必提了,Jetty略有耳闻和Tomcat并列的容易。

那mock是什么呢,带着求知的态度百度一下,没看懂,过!

Spring源码之六-onRefresh()方法_模板方法_06

我们还是重点看Tomcat。进去看TomcatServletWebServerFactory的实现类,new了一个Tomcat的对象,并做了一些Tomcat的设置,什么协议、端口…等等。

@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
   if (this.disableMBeanRegistry) {
      Registry.disableRegistry();
   }
   //创建 Tomcat
   Tomcat tomcat = new Tomcat();
   File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
   tomcat.setBaseDir(baseDir.getAbsolutePath());
   // 同步非阻塞io协议
   Connector connector = new Connector(this.protocol);
   connector.setThrowOnFailure(true);
   tomcat.getService().addConnector(connector);
   customizeConnector(connector);
   tomcat.setConnector(connector);
   tomcat.getHost().setAutoDeploy(false);
   configureEngine(tomcat.getEngine());
   for (Connector additionalConnector : this.additionalTomcatConnectors) {
      tomcat.getService().addConnector(additionalConnector);
   }
   prepareContext(tomcat.getHost(), initializers);
   //这里会创建 TomcatWebServer 实例, 并返回
   return getTomcatWebServer(tomcat);
}

好了,到此就把spirng的模板方法onRefresh()在Springboot中是怎么用的说说清楚了,顺道把Tomcat是怎么内嵌到Springboot中简要的讲解了一下。

貌似有点跑题了,讲onRefresh()方法呢,结果在springboot中饶了一大圈。不过,能让读者更好的理解Spirng和Springboot的关系,能认真的读读也是大有裨益的。

也是真的感叹Spirng作者们的功力之强,Spirng的扩展性有多少的强大。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK