前言
本文主要介绍了关于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