老规矩,我们从spring.factories文件开始。
spring-boot-starter-web下没有spring.factories文件
因此,我们可以从spring.factories文件在spring-boot-autoconfigure中开始
一、dispatcherservlet的注册1.1 把dispatcherservlet注入ioc容器dispatcherservlet是通过dispatcherservletautoconfiguration注册的
@autoconfigureorder(ordered.highest_precedence)@configuration(proxybeanmethods = false)@conditionalonwebapplication(type = type.servlet)@conditionalonclass(dispatcherservlet.class)@autoconfigureafter(servletwebserverfactoryautoconfiguration.class)public class dispatcherservletautoconfiguration { public static final string default_dispatcher_servlet_bean_name = "dispatcherservlet"; public static final string default_dispatcher_servlet_registration_bean_name = "dispatcherservletregistration"; @configuration(proxybeanmethods = false) @conditional(defaultdispatcherservletcondition.class) @conditionalonclass(servletregistration.class) @enableconfigurationproperties({ httpproperties.class, webmvcproperties.class }) protected static class dispatcherservletconfiguration { @bean(name = default_dispatcher_servlet_bean_name) public dispatcherservlet dispatcherservlet(httpproperties httpproperties, webmvcproperties webmvcproperties) { dispatcherservlet dispatcherservlet = new dispatcherservlet(); dispatcherservlet.setdispatchoptionsrequest(webmvcproperties.isdispatchoptionsrequest()); dispatcherservlet.setdispatchtracerequest(webmvcproperties.isdispatchtracerequest()); dispatcherservlet.setthrowexceptionifnohandlerfound(webmvcproperties.isthrowexceptionifnohandlerfound()); dispatcherservlet.setpublishevents(webmvcproperties.ispublishrequesthandledevents()); dispatcherservlet.setenableloggingrequestdetails(httpproperties.islogrequestdetails()); return dispatcherservlet; } @bean @conditionalonbean(multipartresolver.class) @conditionalonmissingbean(name = dispatcherservlet.multipart_resolver_bean_name) public multipartresolver multipartresolver(multipartresolver resolver) { // detect if the user has created a multipartresolver but named it incorrectly return resolver; } } @configuration(proxybeanmethods = false) @conditional(dispatcherservletregistrationcondition.class) @conditionalonclass(servletregistration.class) @enableconfigurationproperties(webmvcproperties.class) @import(dispatcherservletconfiguration.class) protected static class dispatcherservletregistrationconfiguration { @bean(name = default_dispatcher_servlet_registration_bean_name) @conditionalonbean(value = dispatcherservlet.class, name = default_dispatcher_servlet_bean_name) public dispatcherservletregistrationbean dispatcherservletregistration(dispatcherservlet dispatcherservlet, webmvcproperties webmvcproperties, objectprovider<multipartconfigelement> multipartconfig) { dispatcherservletregistrationbean registration = new dispatcherservletregistrationbean(dispatcherservlet, webmvcproperties.getservlet().getpath()); registration.setname(default_dispatcher_servlet_bean_name); registration.setloadonstartup(webmvcproperties.getservlet().getloadonstartup()); multipartconfig.ifavailable(registration::setmultipartconfig); return registration; } } @order(ordered.lowest_precedence - 10) private static class defaultdispatcherservletcondition extends springbootcondition { @override public conditionoutcome getmatchoutcome(conditioncontext context, annotatedtypemetadata metadata) { conditionmessage.builder message = conditionmessage.forcondition("default dispatcherservlet"); configurablelistablebeanfactory beanfactory = context.getbeanfactory(); list<string> dispatchservletbeans = arrays .aslist(beanfactory.getbeannamesfortype(dispatcherservlet.class, false, false)); if (dispatchservletbeans.contains(default_dispatcher_servlet_bean_name)) { return conditionoutcome .nomatch(message.found("dispatcher servlet bean").items(default_dispatcher_servlet_bean_name)); } if (beanfactory.containsbean(default_dispatcher_servlet_bean_name)) { return conditionoutcome.nomatch( message.found("non dispatcher servlet bean").items(default_dispatcher_servlet_bean_name)); } if (dispatchservletbeans.isempty()) { return conditionoutcome.match(message.didnotfind("dispatcher servlet beans").atall()); } return conditionoutcome.match(message.found("dispatcher servlet bean", "dispatcher servlet beans") .items(style.quote, dispatchservletbeans) .append("and none is named " + default_dispatcher_servlet_bean_name)); } } @order(ordered.lowest_precedence - 10) private static class dispatcherservletregistrationcondition extends springbootcondition { @override public conditionoutcome getmatchoutcome(conditioncontext context, annotatedtypemetadata metadata) { configurablelistablebeanfactory beanfactory = context.getbeanfactory(); conditionoutcome outcome = checkdefaultdispatchername(beanfactory); if (!outcome.ismatch()) { return outcome; } return checkservletregistration(beanfactory); } private conditionoutcome checkdefaultdispatchername(configurablelistablebeanfactory beanfactory) { list<string> servlets = arrays .aslist(beanfactory.getbeannamesfortype(dispatcherservlet.class, false, false)); boolean containsdispatcherbean = beanfactory.containsbean(default_dispatcher_servlet_bean_name); if (containsdispatcherbean && !servlets.contains(default_dispatcher_servlet_bean_name)) { return conditionoutcome.nomatch( startmessage().found("non dispatcher servlet").items(default_dispatcher_servlet_bean_name)); } return conditionoutcome.match(); } private conditionoutcome checkservletregistration(configurablelistablebeanfactory beanfactory) { conditionmessage.builder message = startmessage(); list<string> registrations = arrays .aslist(beanfactory.getbeannamesfortype(servletregistrationbean.class, false, false)); boolean containsdispatcherregistrationbean = beanfactory .containsbean(default_dispatcher_servlet_registration_bean_name); if (registrations.isempty()) { if (containsdispatcherregistrationbean) { return conditionoutcome.nomatch(message.found("non servlet registration bean") .items(default_dispatcher_servlet_registration_bean_name)); } return conditionoutcome.match(message.didnotfind("servlet registration bean").atall()); } if (registrations.contains(default_dispatcher_servlet_registration_bean_name)) { return conditionoutcome.nomatch(message.found("servlet registration bean") .items(default_dispatcher_servlet_registration_bean_name)); } if (containsdispatcherregistrationbean) { return conditionoutcome.nomatch(message.found("non servlet registration bean") .items(default_dispatcher_servlet_registration_bean_name)); } return conditionoutcome.match(message.found("servlet registration beans").items(style.quote, registrations) .append("and none is named " + default_dispatcher_servlet_registration_bean_name)); } private conditionmessage.builder startmessage() { return conditionmessage.forcondition("dispatcherservlet registration"); } }}
这也是springboot中ioc容器和web容器是同一个的原因
spring把dispatcherservlet放到容器中后,在dispatcherservlet的初始化中会执行applicationcontextawareprocessor的postprocessbeforeinitialization方法,而其postprocessbeforeinitialization底层如下
private void invokeawareinterfaces(object bean) { if (bean instanceof environmentaware) { ((environmentaware) bean).setenvironment(this.applicationcontext.getenvironment()); } if (bean instanceof embeddedvalueresolveraware) { ((embeddedvalueresolveraware) bean).setembeddedvalueresolver(this.embeddedvalueresolver); } if (bean instanceof resourceloaderaware) { ((resourceloaderaware) bean).setresourceloader(this.applicationcontext); } if (bean instanceof applicationeventpublisheraware) { ((applicationeventpublisheraware) bean).setapplicationeventpublisher(this.applicationcontext); } if (bean instanceof messagesourceaware) { ((messagesourceaware) bean).setmessagesource(this.applicationcontext); } if (bean instanceof applicationcontextaware) { ((applicationcontextaware) bean).setapplicationcontext(this.applicationcontext); } }
而dispatcherservlet是一个applicationcontextaware,所以会执行其setapplicationcontext方法,设置其属性webapplicationcontext
@override public void setapplicationcontext(applicationcontext applicationcontext) { //传入ioc容器 if (this.webapplicationcontext == null && applicationcontext instanceof webapplicationcontext) { this.webapplicationcontext = (webapplicationcontext) applicationcontext; this.webapplicationcontextinjected = true; } }
所以在web容器启动过程会把web容器设置成和ioc容器一样,springmvc容器创建代码如下,参考文章springmvc全注解启动和容器的初始化
protected webapplicationcontext initwebapplicationcontext() { webapplicationcontext rootcontext = webapplicationcontextutils.getwebapplicationcontext(getservletcontext()); webapplicationcontext wac = null; //因为webapplicationcontext这里有值了,所以会进入这里 if (this.webapplicationcontext != null) { //把web容器设置成和ioc容器一样 wac = this.webapplicationcontext; if (wac instanceof configurablewebapplicationcontext) { configurablewebapplicationcontext cwac = (configurablewebapplicationcontext) wac; if (!cwac.isactive()) { if (cwac.getparent() == null) cwac.setparent(rootcontext); } configureandrefreshwebapplicationcontext(cwac); } } } if (wac == null) { wac = findwebapplicationcontext(); wac = createwebapplicationcontext(rootcontext); if (!this.refresheventreceived) { synchronized (this.onrefreshmonitor) { onrefresh(wac); if (this.publishcontext) { string attrname = getservletcontextattributename(); getservletcontext().setattribute(attrname, wac); return wac; }
这里可能要有人问了,为什么在springmvc环境中,this.webapplicationcontext为null,因为在springmvc中dispatcherservlet没有通过spring容器管理
protected void registerdispatcherservlet(servletcontext servletcontext) { string servletname = getservletname(); assert.haslength(servletname, "getservletname() must not return null or empty"); //创建web容器 webapplicationcontext servletappcontext = createservletapplicationcontext(); assert.notnull(servletappcontext, "createservletapplicationcontext() must not return null"); //创建dispatcherservlet对象 frameworkservlet dispatcherservlet = createdispatcherservlet(servletappcontext); assert.notnull(dispatcherservlet, "createdispatcherservlet(webapplicationcontext) must not return null"); dispatcherservlet.setcontextinitializers(getservletapplicationcontextinitializers()); //把dispatcherservlet作为servlet注册到上下文中 servletregistration.dynamic registration = servletcontext.addservlet(servletname, dispatcherservlet); if (registration == null) { throw new illegalstateexception("failed to register servlet with name '" + servletname + "'. " + "check if there is another servlet registered under the same name."); } //容器在启动的时候加载这个servlet,其优先级为1(正数的值越小,该servlet的优先级越高,应用启动时就越先加载) registration.setloadonstartup(1); //设置servlet映射mapping路径 //getservletmappings()是模版方法,需要我们自己配置 registration.addmapping(getservletmappings()); //设置是否支持异步请求 //isasyncsupported默认是true registration.setasyncsupported(isasyncsupported()); //处理自定义的filter进来,一般我们filter不这么加进来,而是自己@webfilter,或者借助spring, //备注:这里添加进来的filter都仅仅只拦截过滤上面注册的dispatchservlet filter[] filters = getservletfilters(); if (!objectutils.isempty(filters)) { for (filter filter : filters) { registerservletfilter(servletcontext, filter); } } //这个很清楚:调用者若相对dispatcherservlet有自己更个性化的参数设置,复写此方法即可 customizeregistration(registration); }
1.2 把dispatcherservlet注入servlet容器springboot中容器是annotationconfigservletwebserverapplicationcontext,其onrefresh()方法如下
@overrideprotected void onrefresh() { super.onrefresh(); try { createwebserver(); //创建servlet容器 } catch (throwable ex) { throw new applicationcontextexception("unable to start web server", ex); }}private void createwebserver() { webserver webserver = this.webserver; servletcontext servletcontext = getservletcontext(); if (webserver == null && servletcontext == null) { servletwebserverfactory factory = getwebserverfactory(); this.webserver = factory.getwebserver(getselfinitializer());//创建容器,并执行所有servletcontextinitializer的onstartup } else if (servletcontext != null) { try { getselfinitializer().onstartup(servletcontext); } catch (servletexception ex) { throw new applicationcontextexception("cannot initialize servlet context", ex); } } initpropertysources(); }
注意,这里他不会执行springservletcontainerinitializer。
流程如下
1、通过getselfinitializer()方法执行容器中所有的servletcontextinitializer
private org.springframework.boot.web.servlet.servletcontextinitializer getselfinitializer() { return this::selfinitialize;}private void selfinitialize(servletcontext servletcontext) throws servletexception { preparewebapplicationcontext(servletcontext); registerapplicationscope(servletcontext); webapplicationcontextutils.registerenvironmentbeans(getbeanfactory(), servletcontext); for (servletcontextinitializer beans : getservletcontextinitializerbeans()) { beans.onstartup(servletcontext); }}
而servletcontextinitializer有个子类servletregistrationbean,通过其addregistration方法注入servlet容器中
@overrideprotected servletregistration.dynamic addregistration(string description, servletcontext servletcontext) { string name = getservletname(); return servletcontext.addservlet(name, this.servlet);}
以上就是springboot中web的启动流程是什么的详细内容。
