| 
 | 
    
 
引言 
 
上一篇博客我们将源码在本地成功运行了,所以在本篇博客中我们从源码层面分析,在启动的过程中,是如何初始化容器的。我们平常都是将我们的服务部署到中,然后修改一下配置文件,启动就可以对外提供服务了,但是我们对于其中的一些流程并不是非常的了解,例如如何加载的web.xml等。这是我们分析和必不可少的过程。 
 
注释源码地址: 
 
一、代码启动 
 
平常我们不论是还是linux,我们都是通过脚本来启动,这对于我们分析源码不是很友好,所以我们需要通过代码启动,启动代码如下: 
 
1 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
=new(); 
 
.(8080); 
 
//new出各层容器,并且维护各层容器的关系 
 
.("/","/"); 
 
.start(); 
 
//阻塞监听端口 
 
.().await(); 
 
启动代码还是非常非常简单,从代码中我们就可以看出,我们本篇博客主要分析的就是()方法和start()方法,通过这两个方法我们就可以找到容器是在什么时候被初始化的。 
 
二、框架 
 
在我们进行分析上面两个方法之前,我们先总结一下的基础框架,其实从我们非常熟悉的.xml配置文件中就可以知道,就是一系列父子容器组成: 
 
--->-->--->(容器),这就是我们从配置文件中分析出来的几个容器,启动时候就是逐层启动容器。 
 
三、创建容器(()) 
 
3.1方法调用流程图 
 
 
 
上面的流程图就是,从源码中逐步分析出来的几个重要的方法,这对于我们分析源码非常有帮助。 
 
3.2源码分析 
 
1)通过反射获得监听器 
 
方法路径:org.....(Hosthost,,); 
 
1 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
8 
 
9 
 
10 
 
11 
 
12 
 
13 
 
14 
 
15 
 
(Hosthost,,){ 
 
//通过反射获得一个监听器, 
 
//通过反射得到的一定是的一个实现类,进入得到实现类(org....) 
 
=null; 
 
try{ 
 
Classclazz=Class.(().()); 
 
=()clazz.().(); 
 
}catch(e){ 
 
//WrapinIAEsincewecan'ttheto 
 
//tothrowthe 
 
thrownewtion(e); 
 
} 
 
(host,,,); 
 
} 
 
2)获得一个容器() 
 
在下面代码中,()方法通过反射加载容器,并且将设置监听,ctx.(); 
 
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 
 
(Hosthost,,, 
 
){ 
 
(host,); 
 
//获得一个容器() 
 
ctx=(host,); 
 
ctx.(); 
 
ctx.(); 
 
if(bapp){ 
 
ctx.(ener()); 
 
} 
 
ctx.((,)); 
 
//把监听器添加到中去 
 
ctx.(); 
 
if(bapp&&()){ 
 
//itfrom(ifitfindsone-it'llhaveduperror) 
 
(()).(()); 
 
} 
 
if(host==null){ 
 
//会逐层创建容器,并维护容器父子关系 
 
().(ctx); 
 
}else{ 
 
host.(ctx); 
 
} 
 
ctx; 
 
} 
 
3)维护各层容器 
 
()方法中得到各层容器,并且维护父亲容器关系,其中包括,容器、容器。并且将容器通过().(ctx);调用中的()方法维护在这个map中。 
 
1 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
8 
 
9 
 
10 
 
11 
 
12 
 
13 
 
Host(){ 
 
//将每一层的容器都new出来 
 
=(); 
 
if(.().>0){ 
 
(Host).()[0]; 
 
} 
 
Hosthost=new(); 
 
host.(); 
 
//维护中的父子容器 
 
().(host); 
 
host; 
 
} 
 
().(host);方法选择调用父类中的方法 
 
 
 
1 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
8 
 
9 
 
 
 
10 
 
11 
 
@ 
 
void(child){ 
 
if(.){ 
 
dp= 
 
new(child); 
 
.(dp); 
 
}else{ 
 
//这里的child参数是容器 
 
(child); 
 
} 
 
} 
 
()方法的核心代码 
 
1 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
8 
 
9 
 
10 
 
11 
 
12 
 
void(child){ 
 
if(log.()) 
 
log.debug("Addchild"+child+""+this); 
 
(){ 
 
if(.get(child.())!=null) 
 
thrownewtion(":Childname'"+ 
 
child.()+ 
 
"'isnot"); 
 
child.(this);//MaythrowIAE 
 
.put(child.(),child); 
 
} 
 
四、启动容器(.start()) 
 
4.1、方法调用流程图 
 
 
 
4.2、源码分析 
 
说明:、、等容器都是继承 
 
所以这里是模板模式的经典应用 
 
1)逐层启动容器 
 
此时的对应的是我们前面创建的 
 
1 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
8 
 
9 
 
voidstart(){ 
 
//防止容器没有创建 
 
(); 
 
//获得容器,并且将得到的容器设置到容器中 
 
(); 
 
//这里的start的实现是在类中实现 
 
//方法是一个模板方法,在启动流程中非常关键 
 
.start(); 
 
} 
 
2)进入start方法 
 
 
 
进入中的start方法,其中核心方法是。 
 
 
 
从上面我们知道现在我们调用的是容器的()方法,所以我们这里选择的是 
 
 
 
方法路径:org...core..() 
 
1 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
8 
 
9 
 
10 
 
11 
 
12 
 
13 
 
14 
 
15 
 
16 
 
void(){ 
 
(T,null); 
 
(.); 
 
s.start(); 
 
//Startour 
 
(){ 
 
//启动容器,一个中可以配置多个容器,每个容器都对应这我们的一个服务应用 
 
for(:){ 
 
//对应.() 
 
.start(); 
 
} 
 
} 
 
} 
 
从上面代码中我们可以看出,启动容器的时候需要启动子容器容器天外神坛源码网,从这里开始就是容器逐层向向内引爆,所以接下来就是开始依次调用各层容器的star方法。在这里就不在赘述。 
 
2)中的()方法核心代码,从这开始启动容器 
 
1 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
8 
 
9 
 
//Startourchild,ifany 
 
//在的流程中方法中加入的,所以这里需要找出来 
 
//这里找出来的就是容器 
 
[]=(); 
 
List>=new(); 
 
for(child:){ 
 
//通过线程池异步的方式启动线程池开始启动容器,进入new 
 
.add(.(new(child))); 
 
} 
 
new(child))方法开始启动容器 
 
1 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
8 
 
9 
 
10 
 
11 
 
12 
 
13 
 
14 
 
15 
 
class{ 
 
child; 
 
(child){ 
 
this.child=child; 
 
} 
 
@ 
 
Voidcall(){ 
 
//开始启动源码城,实际调用.() 
 
child.start(); 
 
null; 
 
} 
 
} 
 
.()方法中的核心代码: 
 
 
 
1 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
8 
 
void(type,data){ 
 
event=new(this,type,data); 
 
//在方法的第一步中,设置的监听的对象 
 
for(:){ 
 
//这里调用的是的()方法 
 
.(event); 
 
} 
 
} 
 
进入到中的()方法 
 
 
 
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 
 
void(event){ 
 
//thewearewith 
 
try{ 
 
=()event.(); 
 
}catch(e){ 
 
log.error(sm.("e",event.()),e); 
 
; 
 
} 
 
//theeventthathas 
 
if(event.().(.T)){ 
 
//完成web.xml的内容解析 
 
(); 
 
}elseif(event.().(.)){ 
 
(); 
 
}elseif(event.().(.)){ 
 
//fortools 
 
if(!=null){ 
 
.(); 
 
} 
 
}elseif(event.().(.)){ 
 
(); 
 
}elseif(event.().(.)){ 
 
init(); 
 
}elseif(event.().(.)){ 
 
(); 
 
} 
 
} 
 
在上面方法中,完成对web.xml的加载和解析,同时加载xml中配置的并且封装成对象。 
 
3)、启动容器源码城,.()中的(())方法 
 
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 
 
([]){ 
 
//"loadon"thatneedtobe 
 
>map=new(); 
 
for(child:){ 
 
//这里的就是我们前面封装的 
 
=()child; 
 
int=.(); 
 
if( 
 
 
; 
 
} 
 
key=.(); 
 
list=map.get(key); 
 
if(list==null){ 
 
list=new(); 
 
map.put(key,list); 
 
} 
 
list.add(); 
 
} 
 
//Loadthe"loadon" 
 
for(list:map.()){ 
 
for(:list){ 
 
try{ 
 
//通过load方法最终会调用的init方法 
 
.load(); 
 
}catch(e){ 
 
().error(sm.("..", 
 
(),.()),.(e)); 
 
//NOTE:load(athat 
 
//fromtheinit())areNOT 
 
//fatalto 
 
//="true"is 
 
if(()){ 
 
false; 
 
} 
 
} 
 
} 
 
} 
 
true; 
 
} 
 
通过load方法最终会调用的init方法。 
 
五、总结 
 
上面内容就是整个是如何调用初始化方法的流程,整个流程小编的理解 |   
 
    
    
        
            【天外神坛】免责声明及帮助 
        
        
1.重要:如果遇到隐藏内容回复后显示为代码状态,直接刷新一下页面即可解决此问题。 
2.本文部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责。 
3.若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。 
4.如果本站有侵犯、不妥之处的资源,请在网站右边客服联系我们。将会第一时间解决! 
5.本站所有内容均由互联网收集整理、网友上传,仅供大家参考、学习,不存在任何商业目的与商业用途。 
6.本站提供的所有资源仅供参考学习使用,版权归原著所有,禁止下载本站资源参与商业和非法行为,请在24小时之内自行删除! 
 
     
 
 
 |