原文地址:https://segmentfault.com/a/1190000041493352
今天帶大家解讀Spirng源碼之六的onRefresh()方法税朴,這是refresh()的其中的一個方法回季,看似是一個空方法,實則他是非常非常重要的正林,對于提高Spring的擴(kuò)展性泡一。
老規(guī)矩,先貼上Spring的核心方法refresh()方法的源碼觅廓,以便讀者可以絲滑入戲鼻忠。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//1、刷新前的準(zhǔn)備
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瞳脓、設(shè)置 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.
//執(zhí)行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實現(xiàn)了這個方法
onRefresh();
// Check for listener beans and register them.
//7、注冊監(jiān)聽器
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()的主要作用耳标,那么文章到這里就結(jié)束了醇坝,感謝閱讀!
開玩笑次坡,只說作用不舉例那和耍流氓沒有什么區(qū)別呼猪,接下來就以Spirng的典型實現(xiàn)Springboot來舉例。
該方法的執(zhí)行時機(jī)是Spring已經(jīng)加載好了一些特殊的bean(內(nèi)置的一些bean砸琅,實現(xiàn)了bean工廠后置處理器的類)之后宋距,在實例化單例bean之前。讓我們來看Springboot是怎么調(diào)用這個模板方法的症脂。
一路的點擊Springboot的核心入口run()方法谚赎,一路找到了我們今天的主角,Spring的refresh()方法中的onRefresh()方法诱篷。
點擊查看Springboot的onRresh()的實現(xiàn)方法壶唤。
有兩個包路徑含有boot的,一定就是Spirngboot的實現(xiàn)方法棕所。
這是Spirng的onRresh()的實現(xiàn)方法闸盔。
比對一下Spirng的onRresh()和SpirngbootRefersh的實現(xiàn)類對比,Springboot多了兩個實現(xiàn)類琳省,ReactiveWebServerApplicationContext類和ServletWebServerApplicationContext類迎吵。
我們分別查看這兩個實現(xiàn)的onRresh()方法都做了什么?
方法名都是createWebServer()方法针贬,以為這兩個方法都是一個方法击费,仔細(xì)一看發(fā)現(xiàn)并不是。
兩個createWebServer()方法做了什么呢桦他?我們debug進(jìn)去摟一眼荡灾。
ReactiveWebServerApplicationContext類的onRresh()方法并沒有執(zhí)行到,見名知意應(yīng)該是跟webServer管理相關(guān)的瞬铸,限于篇幅問題批幌,留個坑暫時放在吧。
ServletWebServerApplicationContext類的onRefresh()方法執(zhí)行到了嗓节,我們進(jìn)去一探究竟荧缘。
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
//第一次進(jìn)來webServer servletContext都是null,會進(jìn)到if分支里面
if (webServer == null && servletContext == null) {
//這里就會來查找ServletWebServerFactory,也就是web容器的工廠,具體看下getWebServerFactory()方法拦宣,
// 還是ServletWebServerApplicationContext這個類的方法
//創(chuàng)建了 TomcatServletWebServerFactory 類
ServletWebServerFactory factory = getWebServerFactory();
//創(chuàng)建 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();
}
核心應(yīng)該是 factory.getWebServer(getSelfInitializer())截粗,這個方法是創(chuàng)建了一個容器信姓。都有哪些容器呢?
我們看一下他的實現(xiàn)類有Jetty绸罗、Mock意推、Tomcat*,Tomcat就不必提了珊蟀,Jetty略有耳聞和Tomcat并列的容易菊值。
那mock是什么呢,帶著求知的態(tài)度百度一下育灸,沒看懂腻窒,過!
我們還是重點看Tomcat磅崭。進(jìn)去看TomcatServletWebServerFactory的實現(xiàn)類儿子,new了一個Tomcat的對象,并做了一些Tomcat的設(shè)置砸喻,什么協(xié)議柔逼、端口......等等。
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
//創(chuàng)建 Tomcat
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
// 同步非阻塞io協(xié)議
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);
//這里會創(chuàng)建 TomcatWebServer 實例, 并返回
return getTomcatWebServer(tomcat);
}
好了割岛,到此就把spirng的模板方法onRefresh()在Springboot中是怎么用的說說清楚了卒落,順道把Tomcat是怎么內(nèi)嵌到Springboot中簡要的講解了一下。
貌似有點跑題了蜂桶,講onRefresh()方法呢,結(jié)果在springboot中饒了一大圈也切。不過扑媚,能讓讀者更好的理解Spirng和Springboot的關(guān)系,能認(rèn)真的讀讀也是大有裨益的雷恃。
也是真的感嘆Spirng作者們的功力之強疆股,Spirng的擴(kuò)展性有多少的強大。