`
wu_quanyin
  • 浏览: 204403 次
  • 性别: Icon_minigender_1
  • 来自: 福建省
社区版块
存档分类
最新评论

Tomcat源码---启动.初始化(加载类包)分析三

阅读更多

一,启动

Tomcat是从org.apache.catalina.startup.Bootstrap#main()开始启动.代码如下:

 

  public static void main(String args[]) {

        if (daemon == null) {
            daemon = new Bootstrap();
            try {
                daemon.init();
            } catch (Throwable t) {
                t.printStackTrace();
                return;
            }
        }

        try {
            String command = "start";
            if (args.length > 0) {
                command = args[args.length - 1];
            }

            if (command.equals("startd")) {
                args[0] = "start";
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stopd")) {
                args[0] = "stop";
                daemon.stop();
            } else if (command.equals("start")) {
                daemon.setAwait(true);
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stop")) {
                daemon.stopServer(args);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }

    }

 

 从以上可以很清楚的看懂tomcat是通过参数的不同进行相应的命令调用.

 启动之前要进行相应的init()初始化,进行相应的环境设置以及包的加,以下我们查看下init的方法.

二,初始化(Bootstrap#init())

 

 public void init()throws Exception
    {

        // Set Catalina path
        setCatalinaHome();
        setCatalinaBase();

       //将tomcat/lib下的jar包进行加载
        initClassLoaders();

        //将classload设置进线程,以便我们使用时进行调用
        Thread.currentThread().setContextClassLoader(catalinaLoader);

        SecurityClassLoad.securityClassLoad(catalinaLoader);

        // Load our startup class and call its process() method
        if (log.isDebugEnabled())
            log.debug("Loading startup class");
        Class startupClass =
            catalinaLoader.loadClass
            ("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.newInstance();

        // 将sharedLoader设置进Catalina类中
        if (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);

        catalinaDaemon = startupInstance;

    }

 

从以上的初始化我们对他一一进行分析

1,

setCatalinaHome();
 setCatalinaBase();

 

     根据源代码主要设置了以下路径:

 

     System.setProperty("catalina.home", System.getProperty("user.dir"));

2,

    //将tomcat/lib下的jar包进行加载
        initClassLoaders();

    tomcat中的加载方式是:

   a) Set up classloaders 

commonLoader (common)-> System Loader

sharedLoader (shared)-> commonLoader -> System Loader

catalinaLoader(server) -> commonLoader -> System Loader

 

    private void initClassLoaders() {
        try {
            commonLoader = createClassLoader("common", null);
            if( commonLoader == null ) {
                // no config file, default to this loader - we might be in a 'single' env.
                commonLoader=this.getClass().getClassLoader();
            }
            catalinaLoader = createClassLoader("server", commonLoader);
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
    }
 

   createClassLoader的加载方式:

   //这个类的主要作用是从 catalina.properties读取信息进行加载

 private ClassLoader createClassLoader(String name, ClassLoader parent)
        throws Exception {
       
   // 获取与ClassLoader相关的属性值,可能为 common.loader,server.loader, shared.loader  
        // 定义在org/apache/catalina/startup/catalina.properties  
        String value = CatalinaProperties.getProperty(name + ".loader");
        if ((value == null) || (value.equals("")))
            return parent;

        ArrayList repositoryLocations = new ArrayList();
        ArrayList repositoryTypes = new ArrayList();
        int i;
 
        StringTokenizer tokenizer = new StringTokenizer(value, ",");
        while (tokenizer.hasMoreElements()) {
            String repository = tokenizer.nextToken();

            // Local repository
            boolean replace = false;
            String before = repository;
            while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) {
                replace=true;
                if (i>0) {
                repository = repository.substring(0,i) + getCatalinaHome() 
                    + repository.substring(i+CATALINA_HOME_TOKEN.length());
                } else {
                    repository = getCatalinaHome() 
                        + repository.substring(CATALINA_HOME_TOKEN.length());
                }
            }
            while ((i=repository.indexOf(CATALINA_BASE_TOKEN))>=0) {
                replace=true;
                if (i>0) {
                repository = repository.substring(0,i) + getCatalinaBase() 
                    + repository.substring(i+CATALINA_BASE_TOKEN.length());
                } else {
                    repository = getCatalinaBase() 
                        + repository.substring(CATALINA_BASE_TOKEN.length());
                }
            }
            if (replace && log.isDebugEnabled())
                log.debug("Expanded " + before + " to " + replace);

            // Check for a JAR URL repository
            try {
                URL url=new URL(repository);
                repositoryLocations.add(repository);
                repositoryTypes.add(ClassLoaderFactory.IS_URL);
                continue;
            } catch (MalformedURLException e) {
                // Ignore
            }

            if (repository.endsWith("*.jar")) {
                repository = repository.substring
                    (0, repository.length() - "*.jar".length());
                repositoryLocations.add(repository);
                repositoryTypes.add(ClassLoaderFactory.IS_GLOB);
            } else if (repository.endsWith(".jar")) {
                repositoryLocations.add(repository);
                repositoryTypes.add(ClassLoaderFactory.IS_JAR);
            } else {
                repositoryLocations.add(repository);
                repositoryTypes.add(ClassLoaderFactory.IS_DIR);
            }
        }

        String[] locations = (String[]) repositoryLocations.toArray(new String[0]);
        Integer[] types = (Integer[]) repositoryTypes.toArray(new Integer[0]);
 
        ClassLoader classLoader = ClassLoaderFactory.createClassLoader
            (locations, types, parent);

        // Retrieving MBean server
        MBeanServer mBeanServer = null;
        if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
            mBeanServer =
                (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);
        } else {
            mBeanServer = MBeanServerFactory.createMBeanServer();
        }

        ///用jmx对该classloader进行管理
        // Register the server classloader
        ObjectName objectName =
            new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
        mBeanServer.registerMBean(classLoader, objectName);

        return classLoader;

    }
 

根据以上的设置tomcat主要对类加载作了以下方式:

 

b) Load startup class (reflection)

org.apache.catalina.startup.Catalina

setParentClassloader -> sharedLoader

Thread.contextClassloader -> catalinaLoader

---------------------------------------------------------------------------------------------------------------------------

以下对java中的类加载进行归纳:

可参考文章:http://blog.chenlb.com/2009/06/java-classloader-architecture.html

 

以上用线程设置classloader的目的是:

java默认的线程上下文类加载器是 系统类加载器(AppClassLoader)。

 

   使用Thread.currentThread().setContextClassLoader(classloader)时,线程上下文 Classloader就变成了指定的Classloader了。此时,在本线程或子线程的任意一处地方,调用Thread.currentThread(). getContextClassLoader(),都可以得到前面设置的Classloader。

 

如果要扩展classloader对类包进行加载也可扩展URLCloassLoader类

 

1
0
分享到:
评论

相关推荐

    JBPM4.4用户手册.doc

    6.7.2. 用户代码类加载器 7. Variables变量 7.1. 变量作用域 7.2. 变量类型 7.3. 更新持久化流程变量 7.4. 声明变量 7.5. 变量历史 8. Scripting脚本 9. Configuration配置 9.1. 工作日历 9.2. Console控制台 9.3. ...

    JAVA上百实例源码以及开源项目源代码

    像坐标控制、旋转矩阵、定时器、生成图像、数据初始化、矩阵乘法、坐标旋转、判断是否是顺时针方向排列、鼠标按下、放开时的动作等,都可在本源码中得以体现。 Java编写的显示器显示模式检测程序 2个目标文件 内容...

    cms后台管理

    将解压后得到的jeecms-3.0.2-final文件夹下的root文件夹更名为jeecms拷贝到tomcat 安装目录下的webapps 文件夹下(例如: D:\Tomcat 6.0\webapps\),启动tomcat,在地址栏中输入http://localhost:8080/jeecms, 您...

    JAVA上百实例源码以及开源项目

    像坐标控制、旋转矩阵、定时器、生成图像、数据初始化、矩阵乘法、坐标旋转、判断是否是顺时针方向排列、鼠标按下、放开时的动作等,都可在本源码中得以体现。 Java编写的显示器显示模式检测程序 2个目标文件 内容...

    JSP动态网页制作基础培训教程源代码.rar

    读者应该确保计算机上安装有SQL Server 2000服务器,启动SQL Server服务后,打开查询分析器,然后执行本章目录下的db.sql文件自动生成并初始化数据库。 2.将本章的代码(文件夹news)拷贝到Tomcat服务器安装目录的...

    leetcode下载-blogNote:个人博客学习笔记

    -SpringMVC源码分析之参数handleMapping初始化如何映射URL //todo 配置文件顺序加载还未分析 SpringBoot学习笔记(五)-SpringBoot如何启动内嵌的tomcat 链表 题目编号 代码 题解 备注 难度 medium 使用双指针法 ...

    java 面试题 总结

    新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。 3.封装: 封装是把...

    超级有影响力霸气的Java面试题大全文档

    新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。 3.封装:  封装...

    Java虚拟机

    第三部分分析了虚拟机的执行子系统,包括类文件结构、虚拟机类加载机制、虚拟机字节码执行引擎。第四部分讲解了程序的编译与代码的优化,阐述了泛型、自动装箱拆箱、条件编译等语法糖的原理;讲解了虚拟机的热点探测...

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    虚拟机类加载机制 / 171 7.1 概述 / 171 7.2 类加载的时机 / 172 7.3 类加载的过程 / 176 7.3.1 加载 / 176 7.3.2 验证 / 178 7.3.3 准备 / 181 7.3.4 解析 / 182 7.3.5 初始化 / 186 7.4 类加载器 ...

Global site tag (gtag.js) - Google Analytics