bootstrap动态初始化,揭开tomcat神秘的面纱之bootstrap初始化

在上文揭开tomcat神秘的面纱之启动脚本中,本菜鸟分析到,最终执行会执行以下命令

/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/bin/java -Djava.util.logging.config.file=/Users/jetty/Documents/software/apache-tomcat-7.0.76/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=/Users/jetty/Documents/software/apache-tomcat-7.0.76/endorsed -classpath /Users/jetty/Documents/software/apache-tomcat7.0.76/bin/bootstrap.jar:/Users/jetty/Documents/software/apache-tomcat-7.0.76/bin/tomcat-juli.jar -Dcatalina.base=/Users/jetty/Documents/software/apache-tomcat-7.0.76 -Dcatalina.home=/Users/jetty/Documents/software/apache-tomcat-7.0.76 -Djava.io.tmpdir=/Users/jetty/Documents/software/apache-tomcat-7.0.76/temporg.apache.catalina.startup.Bootstrap start

简单来说就是

java org.apache.catalina.startup.Bootstrap start这个bootstrap类从何而来?

不由得想到上文提到的启动参数

-classpath /Users/jetty/Documents/software/apache-tomcat7.0.76/bin/bootstrap.jar:/Users/jetty/Documents/software/apache-tomcat-7.0.76/bin/tomcat-juli.jar

可以看到,在jvm参数中指定了classPath参数,其中提到了bootstrap.jar和tomcat-juli.jar关于classPath该参数,本菜鸟开发过程中也一直没有用到过,不得不百度了一下,才了解到是在启动过程中引用到jar的意思。该jar位于bin目录下,如图:

tomcat/bin路径本菜鸟从github上将代码拉了下来,来看看到底tomcat内部是什么样子的,在看代码之前,将《深入剖析tomcat》此书看过了,大学的时候,就已经读过该书,不得不说,毕业后懒惰了,毕业快三年了才想起来重新拿起来读一遍。

public final class Bootstrap {private static final Object daemonLock = new Object(); //初始化并发锁private static volatile Bootstrap daemon = null; //单例private static final File catalinaBaseFile; //jvm启动参数catalina.baseprivate static final File catalinaHomeFile;//jvm启动参数catalina.homeprivate static final Pattern PATH_PATTERN = Pattern.compile("(\".*?\")|(([^,])*)");private Object catalinaDaemon = null;ClassLoader commonLoader = null;//公共类加载器,catalinaLoader,sharedLoader两者共同引用的ClassLoader catalinaLoader = null;//tomcat的jvm类加载器ClassLoader sharedLoader = null;//共享类加载器}

在启动过程中,会首先调用静态方法,将参数catalina.base和catalina.home存放在System的Properties中。在bootstrap的main方法中,首先会将Bootstrap初始化(init),然后加载(load),最后启动(start)。

public static void main(String args[]) {synchronized (daemonLock) {//加锁,初始化一次daemonif (daemon == null) { 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) {/取第一个启动jvm参数为指令,java org.apache.catalina.startup.Bootstrap start 时,取得为startcommand = args[args.length - 1];}if (command.equals("startd")) { //如果为startd,当做start处理args[args.length - 1] = "start";daemon.load(args); //加载daemon.start(); //启动} else if (command.equals("stopd")) {//stopd当做stop处理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);}}

而在初始化过程中,初始化了三个类加载器和catalina对象。

public void init() throws Exception {initClassLoaders();//初始化三个类加载器Thread.currentThread().setContextClassLoader(catalinaLoader);//将当前线程类加载器设置为catalina类加载器SecurityClassLoad.securityClassLoad(catalinaLoader);Class startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");//初始化Catalina对象,Object startupInstance = startupClass.getConstructor().newInstance();// Set the shared extensions class loaderif (log.isDebugEnabled())log.debug("Setting startup class properties");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);method.invoke(startupInstance, paramValues); //利用反射,设置类加载器为sharedLoadercatalinaDaemon = startupInstance;将Catalina对象关联在bootstrap}private void initClassLoaders() { commonLoader = createClassLoader("common", null); catalinaLoader = createClassLoader("server", commonLoader); sharedLoader = createClassLoader("shared", commonLoader);} private ClassLoader createClassLoader(String name, ClassLoader parent)throws Exception {String value = CatalinaProperties.getProperty(name + ".loader");//获取指定类加载器的加载jar包路径common.loader路径为${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jarif ((value == null) || (value.equals("")))return parent;value = replace(value);List repositories = new ArrayList();String[] repositoryPaths = getPaths(value);//获取所有依赖路径,根据URL,GLOB,JAR,DIR依赖路径创建类加载器for (String repository : repositoryPaths) {try {URL url = new URL(repository);repositories.add(new Repository(repository, RepositoryType.URL)); continue;} catch (MalformedURLException e) {}if (repository.endsWith("*.jar")) {repository = repository.substring(0, repository.length() - "*.jar".length());repositories.add(new Repository(repository, RepositoryType.GLOB));} else if (repository.endsWith(".jar")) {repositories.add(new Repository(repository, RepositoryType.JAR));} else {repositories.add(new Repository(repository, RepositoryType.DIR));}}return ClassLoaderFactory.createClassLoader(repositories, parent);}

当第一次传入common,创建common.loader的时候会发生什么?本菜鸟看到,会从CatalinaProperties中获取common.loader的配置路径,而初始化CatalinaProperties程中会去加载tomcat路径/conf/catalina.properties配置,也就是说CatalinaProperties读取的路径先读catalina.properties服务器配置文件,如果没有,读bootstrap.jar包中的catalina.properties文件。

public class CatalinaProperties {private static final Log log = LogFactory.getLog(CatalinaProperties.class);private static Properties properties = null;static {loadProperties();}public static String getProperty(String name) {return properties.getProperty(name);}private static void loadProperties() {InputStream is = null;String fileName = "catalina.properties";String configUrl = System.getProperty("catalina.config");//这里返回为nullif (configUrl != null) {if (configUrl.indexOf('/') == -1) {fileName = configUrl;} else {is = (new URL(configUrl)).openStream();}}if (is == null) { File home = new File(Bootstrap.getCatalinaBase());File conf = new File(home, "conf");File propsFile = new File(conf, fileName);//\/conf/catalina.properties文件读取is = new FileInputStream(propsFile);}if (is == null) {/还没有就从bootstrap.jar包中读取is = CatalinaProperties.class.getResourceAsStream("/org/apache/catalina/startup/catalina.properties");/if (is != null) {properties = new Properties();properties.load(is);//加载properties}if ((is == null)) {properties = new Properties();}Enumeration enumeration = properties.propertyNames();while (enumeration.hasMoreElements()) {String name = (String) enumeration.nextElement();String value = properties.getProperty(name);if (value != null) {System.setProperty(name, value);//存放在System.Properties中}}}}

catalina.properties文件中都有哪些配置?具体如下:

package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,\org.apache.naming.resources.,org.apache.tomcat.package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,\org.apache.jasper.,org.apache.naming.,org.apache.tomcat.common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jarserver.loader=shared.loader=tomcat.util.scan.DefaultJarScanner.jarsToSkip=\bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,websocket-api.jar,\catalina.jar,catalina-ant.jar,catalina-ha.jar,catalina-tribes.jar,\jasper.jar,jasper-el.jar,ecj-*.jar,\tomcat-api.jar,tomcat-util.jar,tomcat-coyote.jar,tomcat-dbcp.jar,\tomcat-jni.jar,tomcat-spdy.jar,\tomcat-i18n-en.jar,tomcat-i18n-es.jar,tomcat-i18n-fr.jar,tomcat-i18n-ja.jar,\tomcat-juli-adapters.jar,catalina-jmx-remote.jar,catalina-ws.jar,\tomcat-jdbc.jar,\tools.jar,\commons-beanutils*.jar,commons-codec*.jar,commons-collections*.jar,\commons-dbcp*.jar,commons-digester*.jar,commons-fileupload*.jar,\commons-httpclient*.jar,commons-io*.jar,commons-lang*.jar,commons-logging*.jar,\commons-math*.jar,commons-pool*.jar,\jstl.jar,taglibs-standard-spec-*.jar,\geronimo-spec-jaxrpc*.jar,wsdl4j*.jar,\ant.jar,ant-junit*.jar,aspectj*.jar,jmx.jar,h2*.jar,hibernate*.jar,httpclient*.jar,\jmx-tools.jar,jta*.jar,log4j.jar,log4j-1*.jar,mail*.jar,slf4j*.jar,\xercesImpl.jar,xmlParserAPIs.jar,xml-apis.jar,\junit.jar,junit-*.jar,hamcrest*.jar,org.hamcrest*.jar,ant-launcher.jar,\cobertura-*.jar,asm-*.jar,dom4j-*.jar,icu4j-*.jar,jaxen-*.jar,jdom-*.jar,\jetty-*.jar,oro-*.jar,servlet-api-*.jar,tagsoup-*.jar,xmlParserAPIs-*.jar,\xom-*.jarorg.apache.catalina.startup.ContextConfig.jarsToSkip=org.apache.catalina.startup.TldConfig.jarsToSkip=tomcat7-websocket.jartomcat.util.buf.StringCache.byte.enabled=true

可以看到,三种类加载器其他配置都可以指定一些其他不同的jar。万事俱备,只欠东风,所有jar包都找到了,最后一步创建类加载器。

public final class ClassLoaderFactory {private static final Log log = LogFactory.getLog(ClassLoaderFactory.class);public static ClassLoader createClassLoader(List repositories,final ClassLoader parent)throws Exception {Set set = new LinkedHashSet();//将所有依赖转换为urlif (repositories != null) {for (Repository repository : repositories){if (repository.getType() == RepositoryType.URL) {URL url = buildClassLoaderUrl(repository.getLocation());set.add(url);} else if (repository.getType() == RepositoryType.DIR) {File directory = new File(repository.getLocation());directory = directory.getCanonicalFile();if (!validateFile(directory, RepositoryType.DIR)) {continue;}URL url = buildClassLoaderUrl(directory);set.add(url);} else if (repository.getType() == RepositoryType.JAR) {File file=new File(repository.getLocation());file = file.getCanonicalFile();if (!validateFile(file, RepositoryType.JAR)) {continue;}URL url = buildClassLoaderUrl(file);set.add(url);} else if (repository.getType() == RepositoryType.GLOB) {File directory=new File(repository.getLocation());directory = directory.getCanonicalFile();if (!validateFile(directory, RepositoryType.GLOB)) {continue;}String filenames[] = directory.list();if (filenames == null) {continue;}for (int j = 0; j < filenames.length; j++) {String filename = filenames[j].toLowerCase(Locale.ENGLISH);if (!filename.endsWith(".jar"))continue;File file = new File(directory, filenames[j]);file = file.getCanonicalFile();if (!validateFile(file, RepositoryType.JAR)) {continue;}URL url = buildClassLoaderUrl(file);set.add(url);}}}}final URL[] array = set.toArray(new URL[set.size()]);//创建类加载器为url类加载器return AccessController.doPrivileged(new PrivilegedAction() {@Overridepublic URLClassLoader run() {if (parent == null)return new URLClassLoader(array);elsereturn new URLClassLoader(array, parent);}});}}
揭开tomcat神秘的面纱之bootstrap初始化 - 简书bootstrap+jQuery实现的动态进度条功能示例_IT技术_社区下 …Bootstrap 4 排版 _Bootstrap中文网Netty 源码分析之 一 揭开 Bootstrap 神秘的红盖头 (客户端 ...bootstrap table插件动态加载表 …打开页面的时候动态初始化下拉选择框-Java-CSDN问答BootStrap selectpicker - SegmentFault 思否Bootstrap popover内容无法动态更改 - ThinbugbootstrapTable如何在初始化表格后再添加一个删除按钮 ...使用bootstrapValidator插件进行动态添加表单元素并校验bootstrap switch组件:切换状态以及初始化状态bootstrap-datetimepicker示例bootstrap动态折叠菜单,按钮拉伸,菜单动态获取数据bootstrap-datetimepicker 设置初始bootstrap-table checkbox(复选框)初始化部分选中bootstrap-datepicker动态赋初值如何实现BootStrapTable的动态表格bootstrap table 初始化中 在columns中能不能对返回的数据进行截取字符串boostrap3表单FormData初始化问题bootstrap-multiselect.js多选下拉框初始化时默认选中初始值解决bootstrap-fileinput无法删除initialPreview初始化预览的文件如何使 Bootstrap Table 初始化、重新加载bootstrap table X-editable插件 输入值初始化问题bootstrap的modal彻底还原恢复页面初始组件及样式(包括清空数据)Bootstrap FileInput编辑时初始化文档/图片到插件内展示bootstrap-duallistbox初始化和取值project_bootstrap:一组脚本,用于在各种框架中初始化项目-源码bootstrap 动态或静态 隐藏某些列BootStrap 初始化表格时实现特定行改变背景颜色Jasny-Bootstrap 的简单实例bootstrap-datetimepicker插件 设置初始值为某天Bootstrap Selcet动态追加optionLayui table 组件的使用之初始化加载数据、数据刷新表格、传参数使用JQuery实现对BootstrapTable复选框checkbox的动态选中bootstrap datetimepicker实现秒钟选择下拉框bootstrap-table动态添加列、动态添加行、单元格点击横向、竖向统计bootstrap-datetimepicker 初始
2020年中国拼图行业前景分析报告2020年中国拼图市场现状分析报告cpa一年过六科的多少人2017年注册会计师考试科目金蝶帮我吧客户端帮我吧助力AIot23x201简便计算小升初简便运算奥数专题讲解小升初玉语凡音苏工玉雕精品惜春是个佛修惜春小侯爷小说免费阅读长旗袍礼服长旗袍报价行情又到日本吃蟹季grinned造句多啦a梦匪伪大结局苹果文件怎么传到电脑里优美短文案体现山川美可入画这句话虚荣国服IOS版下载虚荣苹果版下载10部中学生必看的励志电影比利小子电影免费观看高清完整版