上一章: 初始化 bootstrap.init()
https://blog.csdn.net/weixin_42209307/article/details/108580214
我们回到, org.apache.catalina.startup.Bootstrap#main 方法
daemon.load(args) , daemon 就是我们的bootstrap实例, 在这个里面就会解析server.xml 并且创建各个组件的实例,
并且一层一层向下, 初始化组件
我们这节只分享组件实例化, 下一节分享, 组件的初始化
// Bootstrap.java
public static void main(String args[]) {
// ....
try {
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
// 我们是启动命令会进入这个分支
daemon.setAwait(true);
daemon.load(args);
daemon.start();
if (null == daemon.getServer()) {
System.exit(1);
}
} else if (command.equals("stop")) {
daemon.stopServer(args);
// ...
}
// Bootstrap.java
private void load(String[] arguments) throws Exception {
// Call the load() method
String methodName = "load";
Object param[];
Class<?> paramTypes[];
if (arguments==null || arguments.length==0) {
paramTypes = null;
param = null;
} else {
paramTypes = new Class[1];
paramTypes[0] = arguments.getClass();
param = new Object[1];
param[0] = arguments;
}
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled()) {
log.debug("Calling startup class " + method);
}
method.invoke(catalinaDaemon, param);
}
可以看到是 bootstrap 还是不自己干活, 正如它的翻译, 它只是引导, 它只做了两件事
- 获取Catalina 的 load 方法的反射
- 执行方法
org.apache.catalina.startup.Catalina#load()
// Catalina.java
public void load() {
// 防止重入
if (loaded) {
return;
}
loaded = true;
// 开始时间
long t1 = System.nanoTime();
// 啥也没干, 这个方法是废弃的
initDirs();
// 初始化命名空间, 向内存中添加一下些静态变量, 这个想看的可以自己DEBUG 进去看
initNaming();
// XML 解析器, 我们重点讲这个
Digester digester = createStartDigester();
InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
try {
// 获取server.xml 配置
file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail", file), e);
}
}
//...代码省略
// 这里就是去拿默认的server.xml 配置
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream("server-embed.xml");
inputSource = new InputSource
(getClass().getClassLoader()
.getResource("server-embed.xml").toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail",
"server-embed.xml"), e);
}
}
}
//...代码省略
try {
inputSource.setByteStream(inputStream);
// 将Catalina 对象提供给解析器, 创建的实例都会放到Catalina里面去, 并且设置Root节点
digester.push(this);
// 开始解析, 并且创建对象, 这个我们就不往下跟了, 等有时间, 带各位看看, 因为规则大家都知道了, xml是怎么被解析的, 解析标签以后又该干嘛
digester.parse(inputSource);
} catch (SAXParseException spe) {
log.warn("Catalina.start using " + getConfigFile() + ": " +
spe.getMessage());
return;
} catch (Exception e) {
log.warn("Catalina.start using " + getConfigFile() + ": " , e);
return;
}
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// Ignore
}
}
}
// 这个后面的代码我们下一次再讲, 一步一步慢慢的分析tomcat
// 设置server 的 servlet(Catalina) 容器, 就是Bootstrap中的, 同一个对象, 所以到这里就可以知道, servlet 容器是全局存在的, 同一个实例, 因为server 只有一个
getServer().setCatalina(this);
// -Dcatalina.home=catalina-home
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
// -Dcatalina.base=catalina-home
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
// 初始化console 打印,
initStreams();
// 初始化server <Server/>
try {
// 这里就会一层一层的向下初始化了
getServer().init();
} catch (LifecycleException e) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new java.lang.Error(e);
} else {
log.error("Catalina.start", e);
}
}
// 结束时间
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
}
}
下面就是我们的本节重点了, 组件是怎么实例化的
Digester digester = createStartDigester();
// Catalina.java
protected Digester createStartDigester() {
long t1=System.currentTimeMillis();
// 创建一个解析器对象
Digester digester = new Digester();
// 是否校验
digester.setValidating(false);
// 是否校验xml规则
digester.setRulesValidation(true);
Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
List<String> objectAttrs = new ArrayList<>();
objectAttrs.add("className");
fakeAttributes.put(Object.class, objectAttrs);
// Ignore attribute added by Eclipse for its internal tracking
List<String> contextAttrs = new ArrayList<>();
contextAttrs.add("source");
fakeAttributes.put(StandardContext.class, contextAttrs);
digester.setFakeAttributes(fakeAttributes);
// 是否使用上下文类加载器, 这个类加载器就是在bootstrap.init(), 设置的上下文 sharedLoader
digester.setUseContextClassLoader(true);
// 我们解读这一块代码, 本文全部都是在为这个做铺垫
digester.addObjectCreate("Server",
"org.apache.catalina.core.StandardServer",
"className");
digester.addSetProperties("Server");
digester.addSetNext("Server",
"setServer",
"org.apache.catalina.Server");
digester.addObjectCreate("Server/GlobalNamingResources",
"org.apache.catalina.deploy.NamingResourcesImpl");
digester.addSetProperties("Server/GlobalNamingResources");
digester.addSetNext("Server/GlobalNamingResources",
"setGlobalNamingResources",
"org.apache.catalina.deploy.NamingResourcesImpl");
digester.addObjectCreate("Server/Listener",
null, // MUST be specified in the element
"className");
digester.addSetProperties("Server/Listener");
digester.addSetNext("Server/Listener",
"addLifecycleListener",
"org.apache.catalina.LifecycleListener");
digester.addObjectCreate("Server/Service",
"org.apache.catalina.core.StandardService",
"className");
digester.addSetProperties("Server/Service");
digester.addSetNext("Server/Service",
"addService",
"org.apache.catalina.Service");
digester.addObjectCreate("Server/Service/Listener",
null, // MUST be specified in the element
"className");
digester.addSetProperties("Server/Service/Listener");
digester.addSetNext("Server/Service/Listener",
"addLifecycleListener",
"org.apache.catalina.LifecycleListener");
//Executor
digester.addObjectCreate("Server/Service/Executor",
"org.apache.catalina.core.StandardThreadExecutor",
"className");
digester.addSetProperties("Server/Service/Executor");
digester.addSetNext("Server/Service/Executor",
"addExecutor",
"org.apache.catalina.Executor");
digester.addRule("Server/Service/Connector",
new ConnectorCreateRule());
digester.addRule("Server/Service/Connector",
new SetAllPropertiesRule(new String[]{"executor", "sslImplementationName"}));
digester.addSetNext("Server/Service/Connector",
"addConnector",
"org.apache.catalina.connector.Connector");
digester.addObjectCreate("Server/Service/Connector/SSLHostConfig",
"org.apache.tomcat.util.net.SSLHostConfig");
digester.addSetProperties("Server/Service/Connector/SSLHostConfig");
digester.addSetNext("Server/Service/Connector/SSLHostConfig",
"addSslHostConfig",
"org.apache.tomcat.util.net.SSLHostConfig");
digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
new CertificateCreateRule());
digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
new SetAllPropertiesRule(new String[]{"type"}));
digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate",
"addCertificate",
"org.apache.tomcat.util.net.SSLHostConfigCertificate");
digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
"org.apache.tomcat.util.net.openssl.OpenSSLConf");
digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf");
digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
"setOpenSslConf",
"org.apache.tomcat.util.net.openssl.OpenSSLConf");
digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
"org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd");
digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
"addCmd",
"org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
digester.addObjectCreate("Server/Service/Connector/Listener",
null, // MUST be specified in the element
"className");
digester.addSetProperties("Server/Service/Connector/Listener");
digester.addSetNext("Server/Service/Connector/Listener",
"addLifecycleListener",
"org.apache.catalina.LifecycleListener");
digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",
null, // MUST be specified in the element
"className");
digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");
digester.addSetNext("Server/Service/Connector/UpgradeProtocol",
"addUpgradeProtocol",
"org.apache.coyote.UpgradeProtocol");
// Add RuleSets for nested elements
digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
digester.addRuleSet(new EngineRuleSet("Server/Service/"));
digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
// When the 'engine' is found, set the parentClassLoader.
digester.addRule("Server/Service/Engine",
new SetParentClassLoaderRule(parentClassLoader));
addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
long t2=System.currentTimeMillis();
if (log.isDebugEnabled()) {
log.debug("Digester for server.xml created " + ( t2-t1 ));
}
return digester;
}
看着好多是吧, 不要紧, 我分析几个典例, 相信你一定就看懂了, 先看第一个, server 标签解析, 这个里面的解析都是SAX解析, 一行一行的来的, 消耗内存小
Server 标签
digester.addObjectCreate("Server",
"org.apache.catalina.core.StandardServer",
"className");
digester.addSetProperties("Server");
digester.addSetNext("Server",
"setServer",
"org.apache.catalina.Server");
- digester.addObjectCreate 创建一个解析节点,解析谁呢?
- param1:节点名称 Server
- param2:解析完以后实例化什么, 这里配置看一个全路径类名
- param3:它是什么类型, className, 类名称嘛, 这个很明显就是可以实例化的
- digester.addSetProperties 节点名称和Server对应
- digester.addSetNext 创建完以后干嘛,干嘛呢
- param1:对应节点
- param2:调用的函数 setServer
- param3:传参类型
- 流程就是, 解析节点创建实例 -> 创建实例完成以后放置在那里
- 我们主要看 digester.addSetNext 的第二个参数 , setServer 这个函数在那呢??
- 因为 Server 没有父节点, 所以它的父节点默认就是Root, Root 就是 Catalina, 这个在哪里可以验证?
// 这就是在解析前, 将Catalina设置进去了
// Digester.java
public void push(Object object) {
if (stack.size() == 0) {
root = object;
}
stack.push(object);
}
- 所以可以断定 setServer 是在 Catalina 里面, 事实也是如此
// Catalina.java
public void setServer(Server server) {
this.server = server;
}
Service 标签
- service 标签和 server 标签大概一致
- 只有digester.addObjectCreate 的一个参数可能大部分不是很懂
- Server/Service , 不仅表面的 xml 的节点关系, 还表面了父子关系
- 所以这就是为什么 addService 这个在Catalina里面找不到, 因为它在 父组件 StandardServer 里面
// org.apache.catalina.core.StandardServer#addService
@Override
public void addService(Service service) {
service.setServer(this);
synchronized (servicesLock) {
Service results[] = new Service[services.length + 1];
System.arraycopy(services, 0, results, 0, services.length);
results[services.length] = service;
services = results;
if (getState().isAvailable()) {
try {
service.start();
} catch (LifecycleException e) {
// Ignore
}
}
// Report this property change to interested listeners
support.firePropertyChange("service", null, service);
}
}
到这里我们本章节的任务已经算是完成了, 各位有兴趣的可以去看 组件的默认构造器, 看在实例化的时候都做了些什么操作,
这里我就不带大家去看了, 再以后的分析中, 自然会讲,
下一步, 将带各位查看组件的初始化, 会涉及部分组件的构造器, 才明白是数据是怎么来的