前言
本文主要介绍了关于spring boot中servlet启动过程与原理的相关内容,下面话不多说了,来一起看看详细的介绍吧
启动过程与原理:
1 spring boot 应用启动运行run方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
stopwatch stopwatch = new stopwatch(); stopwatch.start(); configurableapplicationcontext context = null ; failureanalyzers analyzers = null ; configureheadlessproperty(); springapplicationrunlisteners listeners = getrunlisteners(args); listeners.starting(); try { applicationarguments applicationarguments = new defaultapplicationarguments( args); configurableenvironment environment = prepareenvironment(listeners, applicationarguments); banner printedbanner = printbanner(environment); //创建一个applicationcontext容器 context = createapplicationcontext(); analyzers = new failureanalyzers(context); preparecontext(context, environment, listeners, applicationarguments, printedbanner); //刷新ioc容器 refreshcontext(context); afterrefresh(context, applicationarguments); listeners.finished(context, null ); stopwatch.stop(); if ( this .logstartupinfo) { new startupinfologger( this .mainapplicationclass) .logstarted(getapplicationlog(), stopwatch); } return context; } catch (throwable ex) { handlerunfailure(context, listeners, analyzers, ex); throw new illegalstateexception(ex); } |
2 createapplicationcontext():创建ioc容器,如果是web应用则创建annotationconfigembeddedwebapplacation的ioc容器,如果不是,则创建annotationconfigapplication的ioc容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public static final string default_context_class = "org.springframework.context." + "annotation.annotationconfigapplicationcontext" ; /** * the class name of application context that will be used by default for web * environments. */ public static final string default_web_context_class = "org.springframework." + "boot.context.embedded.annotationconfigembeddedwebapplicationcontext" ; protected configurableapplicationcontext createapplicationcontext() { class <?> contextclass = this .applicationcontextclass; if (contextclass == null ) { try { //根据应用环境,创建不同的ioc容器 contextclass = class .forname( this .webenvironment ? default_web_context_class : default_context_class); } catch (classnotfoundexception ex) { throw new illegalstateexception( "unable create a default applicationcontext, " + "please specify an applicationcontextclass" , ex); } } return (configurableapplicationcontext) beanutils.instantiate(contextclass); } |
3 refreshcontext(context) spring boot刷新ioc容器(创建容器对象,并初始化容器,创建容器每一个组件)
1
2
3
4
5
6
7
8
9
10
11
|
private void refreshcontext(configurableapplicationcontext context) { refresh(context); if ( this .registershutdownhook) { try { context.registershutdownhook(); } catch (accesscontrolexception ex) { // not allowed in some environments. } } } |
4 refresh(context);刷新刚才创建的ioc容器
1
2
3
4
|
protected void refresh(applicationcontext applicationcontext) { assert .isinstanceof(abstractapplicationcontext. class , applicationcontext); ((abstractapplicationcontext) applicationcontext).refresh(); } |
5 调用父类的refresh()的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public void refresh() throws beansexception, illegalstateexception { object var1 = this .startupshutdownmonitor; synchronized ( this .startupshutdownmonitor) { this .preparerefresh(); configurablelistablebeanfactory beanfactory = this .obtainfreshbeanfactory(); this .preparebeanfactory(beanfactory); try { this .postprocessbeanfactory(beanfactory); this .invokebeanfactorypostprocessors(beanfactory); this .registerbeanpostprocessors(beanfactory); this .initmessagesource(); this .initapplicationeventmulticaster(); this .onrefresh(); this .registerlisteners(); this .finishbeanfactoryinitialization(beanfactory); this .finishrefresh(); } catch (beansexception var9) { if ( this .logger.iswarnenabled()) { this .logger.warn( "exception encountered during context initialization - cancelling refresh attempt: " + var9); } this .destroybeans(); this .cancelrefresh(var9); throw var9; } finally { this .resetcommoncaches(); } } } |
6 抽象父类abstractapplicationcontext类的子类embeddedwebapplicationcontext的onrefresh方法
1
2
3
4
5
6
7
8
9
10
11
|
@override protected void onrefresh() { super .onrefresh(); try { createembeddedservletcontainer(); } catch (throwable ex) { throw new applicationcontextexception( "unable to start embedded container" , ex); } } |
7 在createembeddedservletcontainer放啊发中会获取嵌入式servlet容器工厂,由容器工厂创建servlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
private void createembeddedservletcontainer() { embeddedservletcontainer localcontainer = this .embeddedservletcontainer; servletcontext localservletcontext = getservletcontext(); if (localcontainer == null && localservletcontext == null ) { //获取嵌入式servlet容器工厂 embeddedservletcontainerfactory containerfactory = getembeddedservletcontainerfactory(); //根据容器工厂获取对应嵌入式servlet容器 this .embeddedservletcontainer = containerfactory .getembeddedservletcontainer(getselfinitializer()); } else if (localservletcontext != null ) { try { getselfinitializer().onstartup(localservletcontext); } catch (servletexception ex) { throw new applicationcontextexception( "cannot initialize servlet context" , ex); } } initpropertysources(); } |
8 从ioc容器中获取servlet容器工厂
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
//embeddedwebapplicationcontext#getembeddedservletcontainerfactory protected embeddedservletcontainerfactory getembeddedservletcontainerfactory() { // use bean names so that we don't consider the hierarchy string[] beannames = getbeanfactory() .getbeannamesfortype(embeddedservletcontainerfactory. class ); if (beannames.length == 0 ) { throw new applicationcontextexception( "unable to start embeddedwebapplicationcontext due to missing " + "embeddedservletcontainerfactory bean." ); } if (beannames.length > 1 ) { throw new applicationcontextexception( "unable to start embeddedwebapplicationcontext due to multiple " + "embeddedservletcontainerfactory beans : " + stringutils.arraytocommadelimitedstring(beannames)); } return getbeanfactory().getbean(beannames[ 0 ], embeddedservletcontainerfactory. class ); } |
9 使用servlet容器工厂获取嵌入式servlet容器,具体使用哪一个容器工厂看配置环境依赖
1
2
|
this .embeddedservletcontainer = containerfactory .getembeddedservletcontainer(getselfinitializer()); |
10 上述创建过程 首先启动ioc容器,接着启动嵌入式servlet容器,接着将ioc容器中剩下没有创建的对象获取出来,比如自己创建的controller
1
2
|
// instantiate all remaining (non-lazy-init) singletons. finishbeanfactoryinitialization(beanfactory); |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
protected void finishbeanfactoryinitialization(configurablelistablebeanfactory beanfactory) { // initialize conversion service for this context. if (beanfactory.containsbean(conversion_service_bean_name) && beanfactory.istypematch(conversion_service_bean_name, conversionservice. class )) { beanfactory.setconversionservice( beanfactory.getbean(conversion_service_bean_name, conversionservice. class )); } // register a default embedded value resolver if no bean post-processor // (such as a propertyplaceholderconfigurer bean) registered any before: // at this point, primarily for resolution in annotation attribute values. if (!beanfactory.hasembeddedvalueresolver()) { beanfactory.addembeddedvalueresolver( new stringvalueresolver() { @override public string resolvestringvalue(string strval) { return getenvironment().resolveplaceholders(strval); } }); } // initialize loadtimeweaveraware beans early to allow for registering their transformers early. string[] weaverawarenames = beanfactory.getbeannamesfortype(loadtimeweaveraware. class , false , false ); for (string weaverawarename : weaverawarenames) { getbean(weaverawarename); } // stop using the temporary classloader for type matching. beanfactory.settempclassloader( null ); // allow for caching all bean definition metadata, not expecting further changes. beanfactory.freezeconfiguration(); // instantiate all remaining (non-lazy-init) singletons. beanfactory.preinstantiatesingletons(); } |
看看 preinstantiatesingletons方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
public void preinstantiatesingletons() throws beansexception { if ( this .logger.isdebugenabled()) { this .logger.debug( "pre-instantiating singletons in " + this ); } list<string> beannames = new arraylist( this .beandefinitionnames); iterator var2 = beannames.iterator(); while ( true ) { while ( true ) { string beanname; rootbeandefinition bd; do { do { do { if (!var2.hasnext()) { var2 = beannames.iterator(); while (var2.hasnext()) { beanname = (string)var2.next(); object singletoninstance = this .getsingleton(beanname); if (singletoninstance instanceof smartinitializingsingleton) { final smartinitializingsingleton smartsingleton = (smartinitializingsingleton)singletoninstance; if (system.getsecuritymanager() != null ) { accesscontroller.doprivileged( new privilegedaction<object>() { public object run() { smartsingleton.aftersingletonsinstantiated(); return null ; } }, this .getaccesscontrolcontext()); } else { smartsingleton.aftersingletonsinstantiated(); } } } return ; } beanname = (string)var2.next(); bd = this .getmergedlocalbeandefinition(beanname); } while (bd.isabstract()); } while (!bd.issingleton()); } while (bd.islazyinit()); if ( this .isfactorybean(beanname)) { final factorybean<?> factory = (factorybean) this .getbean( "&" + beanname); boolean iseagerinit; if (system.getsecuritymanager() != null && factory instanceof smartfactorybean) { iseagerinit = (( boolean )accesscontroller.doprivileged( new privilegedaction< boolean >() { public boolean run() { return ((smartfactorybean)factory).iseagerinit(); } }, this .getaccesscontrolcontext())).booleanvalue(); } else { iseagerinit = factory instanceof smartfactorybean && ((smartfactorybean)factory).iseagerinit(); } if (iseagerinit) { this .getbean(beanname); } } else { //注册bean this .getbean(beanname); } } } } |
是使用getbean方法来通过反射将所有未创建的实例创建出来
使用嵌入式servlet容器:
优点: 简单,便携
缺点: 默认不支持jsp,优化定制比较复杂
使用外置servlet容器的步骤:
1 必须创建war项目,需要剑豪web项目的目录结构
2 嵌入式tomcat依赖scope指定provided
3 编写springbootservletinitializer类子类,并重写configure方法
1
2
3
4
5
6
7
|
public class servletinitializer extends springbootservletinitializer { @override protected springapplicationbuilder configure(springapplicationbuilder application) { return application.sources(springboot04webjspapplication. class ); } } |
4 启动服务器
jar包和war包启动区别
jar包:执行springbootapplication的run方法,启动ioc容器,然后创建嵌入式servlet容器
war包: 先是启动servlet服务器,服务器启动springboot应用(springbootservletinitizer),然后启动ioc容器
servlet 3.0+规则
1 服务器启动(web应用启动),会创建当前web应用里面所有jar包里面的servletcontainerlnitializer实例
2 servletcontainerinitializer的实现放在jar包的meta-inf/services文件夹下
3 还可以使用@handlestypes注解,在应用启动的时候加载指定的类。
外部tomcat流程以及原理
① 启动tomcat
② 根据上述描述的servlet3.0+规则,可以在spring的web模块里面找到有个文件名为javax.servlet.servletcontainerinitializer的文件,而文件的内容为org.springframework.web.springservletcontainerinitializer,用于加载springservletcontainerinitializer类
③看看springservletcontainerinitializer定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
@handlestypes (webapplicationinitializer. class ) public class springservletcontainerinitializer implements servletcontainerinitializer { /** * delegate the {@code servletcontext} to any {@link webapplicationinitializer} * implementations present on the application classpath. * <p>because this class declares @{@code handlestypes(webapplicationinitializer.class)}, * servlet 3.0+ containers will automatically scan the classpath for implementations * of spring's {@code webapplicationinitializer} interface and provide the set of all * such types to the {@code webappinitializerclasses} parameter of this method. * <p>if no {@code webapplicationinitializer} implementations are found on the classpath, * this method is effectively a no-op. an info-level log message will be issued notifying * the user that the {@code servletcontainerinitializer} has indeed been invoked but that * no {@code webapplicationinitializer} implementations were found. * <p>assuming that one or more {@code webapplicationinitializer} types are detected, * they will be instantiated (and <em>sorted</em> if the @{@link * org.springframework.core.annotation.order @order} annotation is present or * the {@link org.springframework.core.ordered ordered} interface has been * implemented). then the {@link webapplicationinitializer#onstartup(servletcontext)} * method will be invoked on each instance, delegating the {@code servletcontext} such * that each instance may register and configure servlets such as spring's * {@code dispatcherservlet}, listeners such as spring's {@code contextloaderlistener}, * or any other servlet api componentry such as filters. * @param webappinitializerclasses all implementations of * {@link webapplicationinitializer} found on the application classpath * @param servletcontext the servlet context to be initialized * @see webapplicationinitializer#onstartup(servletcontext) * @see annotationawareordercomparator */ @override public void onstartup(set< class <?>> webappinitializerclasses, servletcontext servletcontext) throws servletexception { list<webapplicationinitializer> initializers = new linkedlist<webapplicationinitializer>(); if (webappinitializerclasses != null ) { for ( class <?> waiclass : webappinitializerclasses) { // be defensive: some servlet containers provide us with invalid classes, // no matter what @handlestypes says... if (!waiclass.isinterface() && !modifier.isabstract(waiclass.getmodifiers()) && webapplicationinitializer. class .isassignablefrom(waiclass)) { try { //为所有的webapplicationinitializer类型创建实例,并加入集合中 initializers.add((webapplicationinitializer) waiclass.newinstance()); } catch (throwable ex) { throw new servletexception( "failed to instantiate webapplicationinitializer class" , ex); } } } } if (initializers.isempty()) { servletcontext.log( "no spring webapplicationinitializer types detected on classpath" ); return ; } servletcontext.log(initializers.size() + " spring webapplicationinitializers detected on classpath" ); annotationawareordercomparator.sort(initializers); //调用每一个webapplicationinitializer实例的onstartup方法 for (webapplicationinitializer initializer : initializers) { initializer.onstartup(servletcontext); } } } |
在上面一段长长的注释中可以看到,springservletcontainerinitializer将@handlestypes(webapplicationinitializer.class)标注的所有webapplicationinitializer这个类型的类都传入到onstartup方法的set参数中,并通过反射为这些webapplicationinitializer类型的类创建实例;
④ 方法最后,每一个webapplicationinitilizer实现调用自己onstartup方法
⑤ 而webapplicationinitializer有个抽象实现类springbootservletinitializer(记住我们继承了该抽象类),则会调用每一个webapplicationinitializer实例(包括springbootservletinitializer)的onstartup方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
public abstract class springbootservletinitializer implements webapplicationinitializer { //other code... @override public void onstartup(servletcontext servletcontext) throws servletexception { // logger initialization is deferred in case a ordered // logservletcontextinitializer is being used this .logger = logfactory.getlog(getclass()); //创建ioc容器 webapplicationcontext rootappcontext = createrootapplicationcontext( servletcontext); if (rootappcontext != null ) { servletcontext.addlistener( new contextloaderlistener(rootappcontext) { @override public void contextinitialized(servletcontextevent event) { // no-op because the application context is already initialized } }); } else { this .logger.debug( "no contextloaderlistener registered, as " + "createrootapplicationcontext() did not " + "return an application context" ); } } protected webapplicationcontext createrootapplicationcontext( servletcontext servletcontext) { //创建spring应用构建器,并进行相关属性设置 springapplicationbuilder builder = createspringapplicationbuilder(); standardservletenvironment environment = new standardservletenvironment(); environment.initpropertysources(servletcontext, null ); builder.environment(environment); builder.main(getclass()); applicationcontext parent = getexistingrootwebapplicationcontext(servletcontext); if (parent != null ) { this .logger.info( "root context already created (using as parent)." ); servletcontext.setattribute( webapplicationcontext.root_web_application_context_attribute, null ); builder.initializers( new parentcontextapplicationcontextinitializer(parent)); } builder.initializers( new servletcontextapplicationcontextinitializer(servletcontext)); builder.contextclass(annotationconfigembeddedwebapplicationcontext. class ); //调用configure方法,创建war类型的web项目后,由于编写springbootservletinitializer的子类重写configure方法,所以此处调用的是我们定义的子类重写的configure方法 builder = configure(builder); //通过构建器构建了一个spring应用 springapplication application = builder.build(); if (application.getsources().isempty() && annotationutils .findannotation(getclass(), configuration. class ) != null ) { application.getsources().add(getclass()); } assert .state(!application.getsources().isempty(), "no springapplication sources have been defined. either override the " + "configure method or add an @configuration annotation" ); // ensure error pages are registered if ( this .registererrorpagefilter) { application.getsources().add(errorpagefilterconfiguration. class ); } //启动spring应用 return run(application); } //spring应用启动,创建并返回ioc容器 protected webapplicationcontext run(springapplication application) { return (webapplicationcontext) application.run(); } } |
springbootservletinitializer实例执行onstartup方法的时候会通过createrootapplicationcontext方法来执行run方法,接下来的过程就同以jar包形式启动的应用的run过程一样了,在内部会创建ioc容器并返回,只是以war包形式的应用在创建ioc容器过程中,不再创建servlet容器了。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://www.cnblogs.com/developerxiaofeng/p/9081689.html