前言:
此时同学们对“pid控制算法源码”都比较重视,咱们都需要剖析一些“pid控制算法源码”的相关内容。那么小编在网络上搜集了一些有关“pid控制算法源码””的相关文章,希望朋友们能喜欢,咱们一起来了解一下吧!从startup.sh入手
os400=falsecase "`uname`" inOS400*) os400=true;;esacPRG="$0"while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`/"$link" fidonePRGDIR=`dirname "$PRG"`EXECUTABLE=catalina.shif $os400; then evalelse if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then echo "Cannot find $PRGDIR/$EXECUTABLE" echo "The file is absent or does not have execute permission" echo "This file is needed to run this program" exit 1 fifiexec "$PRGDIR"/"$EXECUTABLE" start "$@"
整个脚本核心就是最后一句代码, EXECUTABLE变量是catalina.sh, 代表执行catalina.sh, 参数是start, 再去对比了shutdown.sh, 两个脚本的核心都是调用catalina.sh传递的变量不同。
浏览catalina.sh脚本
整个脚本很长,我这里之截图了我们关心的脚本内容。 这段代码里, 除了能看到参数传递start, 最后会输出Tomcat started外,能看到调用了org.apache.catalina.startup.Bootstrap, 也就是说找到我们的程序入口,或者说找到了我们的程序的main函数。
shift eval $_NOHUP "\"$_RUNJAVA\"" "\"$CATALINA_LOGGING_CONFIG\"" $LOGGING_MANAGER "$JAVA_OPTS" "$CATALINA_OPTS" \ -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \ -classpath "\"$CLASSPATH\"" \ -Djava.security.manager \ -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \ -Dcatalina.base="\"$CATALINA_BASE\"" \ -Dcatalina.home="\"$CATALINA_HOME\"" \ -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ org.apache.catalina.startup.Bootstrap "$@" start \ >> "$CATALINA_OUT" 2>&1 "&" else eval $_NOHUP "\"$_RUNJAVA\"" "\"$CATALINA_LOGGING_CONFIG\"" $LOGGING_MANAGER "$JAVA_OPTS" "$CATALINA_OPTS" \ -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \ -classpath "\"$CLASSPATH\"" \ -Dcatalina.base="\"$CATALINA_BASE\"" \ -Dcatalina.home="\"$CATALINA_HOME\"" \ -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ org.apache.catalina.startup.Bootstrap "$@" start \ >> "$CATALINA_OUT" 2>&1 "&" fi if [ ! -z "$CATALINA_PID" ]; then echo $! > "$CATALINA_PID" fi echo "Tomcat started."
看到这里我们做个小小的总结:Tomcat本质上也是一个java程序,因此startup.sh会启动一个jvm来运行tomcat的启动类Bootstrap.java。
Bootstrap类核心功能静态构造器部分, 主要初始化了CATALINA_HOME和CATALINA_BASE两个变量内容main函数方法部分一,创建和初始化daemon, 创建三个类加载器main函数方法部分二,控制tomcat的启动和停止从Bootstrap.main方法开始
开始main方法之前,首先看两个关键属性.
/*************守护进程对象**********/private static volatile Bootstrap daemon = null;/***守护程序用的catalina对象***/private Object catalinaDaemon = null;Bootstrap#main
public static void main(String args[]) { synchronized (daemonLock) { if (daemon == null) { //初始化完成之前,不要对daemon赋值 Bootstrap bootstrap = new Bootstrap(); try { //调用初始化方法, 完成加载器的配置和初始化器的准备 bootstrap.init(); } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap; } else { //当作为服务正在运行时,如果调用停止方法,这将在一个新线程上进行,以确保使用正确的类加载器,防止出现未找到类的异常 Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } } 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); //Bootstrap加载 daemon.load(args); //Bootstrap启动 daemon.start(); if (null == daemon.getServer()) { System.exit(1); } } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null == daemon.getServer()) { System.exit(1); } System.exit(0); } else { } }
//Bootstrap.initpublic void init() throws Exception { //初始化类的三个加载器 initClassLoaders(); //设置线程类加载器, 将容器的加载器传入 Thread.currentThread().setContextClassLoader(catalinaLoader); //加载安全类加载器 SecurityClassLoad.securityClassLoad(catalinaLoader); //通过反射加载catalina Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); //创建对象 Object startupInstance = startupClass.getConstructor().newInstance(); String methodName = "setParentClassLoader"; Class<?> paramTypes[] = new Class[1]; //将类加载器作为参数传递 paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object paramValues[] = new Object[1]; paramValues[0] = sharedLoader; //共享加载器 Method method = startupInstance.getClass().getMethod(methodName, paramTypes); //对类加载器进行初始化赋值 //调用catalina类内部的setParentClassLoader方法对catalina类内部的类加载赋值 method.invoke(startupInstance, paramValues); //将创建好的startupInstance对象赋值给catalinaDaemon catalinaDaemon = startupInstance;}Catalina#load
Catalina类的load方法核心就解析config/server.xml并创建Server组件实例, 也就是我们在tomcat整体架构章节里了解的一个tomcat只有一个Server实例。 这部分代码块,我删掉了注释代码,try...catch, 只留下了核心业务代码。
public void load() { loaded = true; long t1 = System.nanoTime(); initDirs(); initNaming(); //利用digester类解析server.xml,得到容器的配置 Digester digester = createStartDigester(); InputSource inputSource = null; InputStream inputStream = null; File file = null; file = configFile(); inputStream = new FileInputStream(file); inputSource = new InputSource(file.toURI().toURL().toString()); if (inputStream == null) { inputStream = getClass().getClassLoader().getResourceAsStream(getConfigFile()); inputSource = new InputSource(getClass().getClassLoader().getResource(getConfigFile()).toString()); } if (inputStream == null) { inputStream = getClass().getClassLoader().getResourceAsStream("server-embed.xml"); inputSource = new InputSource(getClass().getClassLoader().getResource("server-embed.xml").toString()); } if (inputStream == null || inputSource == null) { return; } try { inputSource.setByteStream(inputStream); digester.push(this); digester.parse(inputSource); } catch (SAXParseException spe) { return; } catch (Exception e) { return; } getServer().setCatalina(this); getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile()); getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile()); initStreams(); //服务器执行初始化 开始调用的Server的初始化方法注意Server是一个接口 getServer().init();}Catalina#start
public void start() { if (getServer() == null) { load(); } if (getServer() == null) { return; } long t1 = System.nanoTime(); //开始一个Server实例 try { getServer().start(); } catch (LifecycleException e) { log.fatal(sm.getString("catalina.serverStartFail"), e); try { getServer().destroy(); } catch (LifecycleException e1) { log.debug("destroy() failed for failed Server ", e1); } return; } long t2 = System.nanoTime(); if(log.isInfoEnabled()) { log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms"); } if (useShutdownHook) { if (shutdownHook == null) { shutdownHook = new CatalinaShutdownHook(); } Runtime.getRuntime().addShutdownHook(shutdownHook); LogManager logManager = LogManager.getLogManager(); if (logManager instanceof ClassLoaderLogManager) { ((ClassLoaderLogManager) logManager).setUseShutdownHook(false); } } if (await) { await(); stop(); }}
从Bootstrap#createStartDigester方法中可以看到Server接口的实现类是StandardServer.
digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");
Server接口继承了Lifecycle接口
StandardServer类继承了抽象类LifecycleMBeanBase,同时实现了Server接口
LifecycleMBeanBase抽象类又继承了抽象类LifecycleBase, 而LifecycleBase抽象类又实现了Lifecycle接口
通过前面的调用链看出来Catalina.start会调用Server接口的start方法,而StandardServer实现类的start方法就追溯到了LifeCycleBase抽象的start方法, 这个类里定义了抽象方法startInternal让子类去实现。 在start方法中也调用了startInternal方法。
StandardServer类图StandardServer#startInternal
protected void startInternal() throws LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, null); setState(LifecycleState.STARTING); globalNamingResources.start(); synchronized (servicesLock) { //这里启动定义的多个service for (Service service : services) { service.start(); } }}
根据Server的实现类StandardServer类,我顺便查看了其所在包, 看到了整个tomcat用到的核心组件的实现类都在这里了,比如StandardEngine, StandardService,StandardHost, 可以查看其他的实现类结构。
总结
结合上面的两张图片,以及上述的源码分析,我们就能总结出来整个startup.sh过程中完成的任务
Tomcat本质上是一个java程序,因此startup脚本会启动一个jvm来运行tomcat的启动类Bootstrap.Bootstrap的主要任务就是初始化tomcat的类加载器,并且创建Catalina.Catalina是一个启动类,通过解析Server.xml创建相应组件,通过调用Server接口实现类去启动Server.StandardServer通过调用父类LifecycleBase的start方法,并且重写startInternal方法来启动Server和启动Service.Service组件的职责就是管理连接器和顶层容器,他会调用连接器和顶层容器的start方法.容器组件负责启动管理子容器,并且调用Host的start方法, 将各层容器启动起来。参考资料
标签: #pid控制算法源码