• Tomcat启动分析(Tomcat7.0)


    1)bin目录下的bootstrap.jar中的main方法启动Tomcat

    org.apache.catalina.startup.Bootstrap类下的main方法

    可以看到Bootstrap类使用单例方式在main方法中初始化Bootstrap对象

    private static Bootstrap daemon = null;
    private Object catalinaDaemon = null;
    protected ClassLoader commonLoader = null;
    protected ClassLoader catalinaLoader = null;
    protected ClassLoader sharedLoader = null;
    

     调用Bootstrap对象的init()方法

    public static void main(String[] args)
    {
        if (daemon == null)
        {
          Bootstrap bootstrap = new Bootstrap();
          try {
            bootstrap.init();
          } catch (Throwable t) {
            handleThrowable(t);
            t.printStackTrace();
            return;
          }
          daemon = bootstrap;
        }
        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();
          } 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 {
            log.warn(new StringBuilder().append("Bootstrap: command "").append(command).append("" does not exist.").toString());
          }
        }
        catch (Throwable t) {
          if (((t instanceof InvocationTargetException)) && (t.getCause() != null))
          {
            t = t.getCause();
          }
          handleThrowable(t);
          t.printStackTrace();
          System.exit(1);
        }
      }
      
    

    Bootstrap对象的init()方法,引导类Bootstrap负责引导,在其init方法内部创建容器启动所需的类加载器,以及用于JMX监控的MBeanServer

    public void init()
        throws Exception
      {
        setCatalinaHome();
        setCatalinaBase();
        
        initClassLoaders();
        
        Thread.currentThread().setContextClassLoader(this.catalinaLoader);
        
        SecurityClassLoad.securityClassLoad(this.catalinaLoader);
        
        if (log.isDebugEnabled())
          log.debug("Loading startup class");
        Class<?> startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
        
        Object startupInstance = startupClass.newInstance();
        
        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] = this.sharedLoader;
        Method method = startupInstance.getClass().getMethod(methodName, paramTypes);
        
        method.invoke(startupInstance, paramValues);
        
        this.catalinaDaemon = startupInstance;
      }
      
    

    仍然在Bootstrap类中,初始化所需要的类加载器

    private void initClassLoaders()
      {
        try
        {
          this.commonLoader = createClassLoader("common", null);
          if (this.commonLoader == null)
          {
            this.commonLoader = getClass().getClassLoader();
          }
          this.catalinaLoader = createClassLoader("server", this.commonLoader);
          this.sharedLoader = createClassLoader("shared", this.commonLoader);
        } catch (Throwable t) {
          handleThrowable(t);
          log.error("Class loader creation threw exception", t);
          System.exit(1);
        }
      }
    

     

    我们继续看到main方法中调用了Bootstrap对象的load(args)方法和start()方法

    daemon.load(args);
    daemon.start();

    我们看到load(args)方法,Bootstrap调用Catalina的load()方法加载Server的配置(也就是server.xml),将加载的配置信息委托给Digester类进行相关内容的解析。

    通过反射调用了Bootstrap对象中catalinaDaemon对象的load()方法,

    private void load(String[] arguments)
        throws Exception
      {
        String methodName = "load";
        Object[] param;
        Class<?>[] paramTypes;
        Object[] param; if ((arguments == null) || (arguments.length == 0)) {
          Class<?>[] paramTypes = null;
          param = null;
        } else {
          paramTypes = new Class[1];
          paramTypes[0] = arguments.getClass();
          param = new Object[1];
          param[0] = arguments;
        }
        Method method = this.catalinaDaemon.getClass().getMethod(methodName, paramTypes);
        
        if (log.isDebugEnabled())
          log.debug(new StringBuilder().append("Calling startup class ").append(method).toString());
        method.invoke(this.catalinaDaemon, param);
      }
    

      

    我们可以看到在上面的init()方法中初始化了org.apache.catalina.startup.Catalina对象,通过之前初始化的catalinaLoader类加载器

    该类在lib包下的catalina.jar包中

     Class<?> startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
        
        Object startupInstance = startupClass.newInstance();
        
        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] = this.sharedLoader;
        Method method = startupInstance.getClass().getMethod(methodName, paramTypes);
        
        method.invoke(startupInstance, paramValues);
        
        this.catalinaDaemon = startupInstance;
    

      

    我们看该类中的load方法是如何加载server.xml文件的。

    public void load()
      {
        long t1 = System.nanoTime();
        
        initDirs();
        
        initNaming();
        
        Digester digester = createStartDigester();
        
        InputSource inputSource = null;
        InputStream inputStream = null;
        File file = null;
        try {
          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", new Object[] { file }), e);
          }
        }
        if (inputStream == null) {
          try {
            inputStream = getClass().getClassLoader().getResourceAsStream(getConfigFile());
            
            inputSource = new InputSource(getClass().getClassLoader().getResource(getConfigFile()).toString());
          }
          catch (Exception e)
          {
            if (log.isDebugEnabled()) {
              log.debug(sm.getString("catalina.configFail", new Object[] { getConfigFile() }), e);
            }
          }
        }
        
        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", new Object[] { "server-embed.xml" }), e);
            }
          }
        }
        
        if ((inputStream == null) || (inputSource == null)) {
          if (file == null) {
            log.warn(sm.getString("catalina.configFail", new Object[] { getConfigFile() + "] or [server-embed.xml]" }));
          }
          else {
            log.warn(sm.getString("catalina.configFail", new Object[] { file.getAbsolutePath() }));
            
            if ((file.exists()) && (!file.canRead())) {
              log.warn("Permissions incorrect, read permission is not allowed on the file.");
            }
          }
          return;
        }
        try
        {
          inputSource.setByteStream(inputStream);
          digester.push(this);
          digester.parse(inputSource);
          
          try
          {
            inputStream.close();
          }
          catch (IOException e) {}
          
          getServer().setCatalina(this);
        }
        catch (SAXParseException spe)
        {
          log.warn("Catalina.start using " + getConfigFile() + ": " + spe.getMessage()); return;
        }
        catch (Exception e)
        {
          log.warn("Catalina.start using " + getConfigFile() + ": ", e); return;
        }
        finally {
          try {
            inputStream.close();
          }
          catch (IOException e) {}
        }
        
        initStreams();
        
        try
        {
          getServer().init();
        } catch (LifecycleException e) {
          if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
            throw new Error(e);
          }
          log.error("Catalina.start", e);
        }
        
        long t2 = System.nanoTime();
        if (log.isInfoEnabled()) {
          log.info("Initialization processed in " + (t2 - t1) / 1000000L + " ms");
        }
      }
      
      public void load(String[] args)
      {
        try
        {
          if (arguments(args)) {
            load();
          }
        } catch (Exception e) {
          e.printStackTrace(System.out);
        }
      }
    
    protected boolean arguments(String[] args)
      {
        boolean isConfig = false;
        
        if (args.length < 1) {
          usage();
          return false;
        }
        
        for (int i = 0; i < args.length; i++) {
          if (isConfig) {
            this.configFile = args[i];
            isConfig = false;
          } else if (args[i].equals("-config")) {
            isConfig = true;
          } else if (args[i].equals("-nonaming")) {
            setUseNaming(false);
          } else { if (args[i].equals("-help")) {
              usage();
              return false; }
            if (args[i].equals("start")) {
              this.starting = true;
              this.stopping = false;
            } else if (args[i].equals("configtest")) {
              this.starting = true;
              this.stopping = false;
            } else if (args[i].equals("stop")) {
              this.starting = false;
              this.stopping = true;
            } else {
              usage();
              return false;
            }
          }
        }
        return true;
      }

    看到Catalina类当中的变量,表明解析文件的位置。

    protected String configFile = "conf/server.xml";
    
    protected File configFile()
      {
        File file = new File(this.configFile);
        if (!file.isAbsolute()) {
          file = new File(System.getProperty("catalina.base"), this.configFile);
        }
        return file;
      }
    

    看到configFile方法创建File对象的过程

    我们将看到load方法中调用getServer().init()调用 Server对象的init方法。

    Catalina获取到Server的配置信息后,执行StandardServer容器的init()方法。Tomcat的所有容器类都实现了统一的Lifecycle接口,由基类LifecycleBase提供统一的init方法来负责处理容器的状态,调用模板方法initInternal来处理各个容器自身所负责的内容。关于Tomcat的容器结构可以参看本系列文章的《Tomcat7源码解读(一)——容器静态结构概述》。StandardServer容器在其initInternal()方法中完成Mbean的设定,GlobalNamingResources的初始化和类加载器的设置。然后执行StandardService容器的init方法。

    StandardService同StandardServer容器,由基类LifecycleBase完成容器的生命周期状态设定,而在initInternal()方法中启动Container,Executor,Connector的init方法

    StandardService类位于lib包下的catalina.jar包中,

    org.apache.catalina.core.StandardService的父类中有init方法,

    public final synchronized void init()
        throws LifecycleException
      {
        if (!this.state.equals(LifecycleState.NEW)) {
          invalidTransition("before_init");
        }
        setStateInternal(LifecycleState.INITIALIZING, null, false);
        try
        {
          initInternal();
        } catch (Throwable t) {
          ExceptionUtils.handleThrowable(t);
          setStateInternal(LifecycleState.FAILED, null, false);
          throw new LifecycleException(sm.getString("lifecycleBase.initFail", new Object[] { toString() }), t);
        }
        
        setStateInternal(LifecycleState.INITIALIZED, null, false);
      }
      
    

    是在org.apache.catalina.util.LifecycleBase类当中,调用了initInternal()方法。

    看到LifecyceBase类的父类中

    protected void initInternal()
        throws LifecycleException
      {
        if (this.oname == null) {
          this.mserver = Registry.getRegistry(null, null).getMBeanServer();
          
          this.oname = register(this, getObjectNameKeyProperties());
        }
      }
    
    protected void initInternal()
        throws LifecycleException
      {
        super.initInternal();
        
        this.onameStringCache = register(new StringCache(), "type=StringCache");
        
        MBeanFactory factory = new MBeanFactory();
        factory.setContainer(this);
        this.onameMBeanFactory = register(factory, "type=MBeanFactory");
        
        this.globalNamingResources.init();
        
        if (getCatalina() != null) {
          ClassLoader cl = getCatalina().getParentClassLoader();
          
          while ((cl != null) && (cl != ClassLoader.getSystemClassLoader())) {
            if ((cl instanceof URLClassLoader)) {
              URL[] urls = ((URLClassLoader)cl).getURLs();
              for (URL url : urls) {
                if (url.getProtocol().equals("file")) {
                  try {
                    File f = new File(url.toURI());
                    if ((f.isFile()) && (f.getName().endsWith(".jar")))
                    {
                      ExtensionValidator.addSystemResource(f);
                    }
                  }
                  catch (URISyntaxException e) {}catch (IOException e) {}
                }
              }
            }
            
            cl = cl.getParent();
          }
        }
        
        for (int i = 0; i < this.services.length; i++) {
          this.services[i].init();
        }
      }
    

      

    看到Bootstrap类当中调用玩load方法之后,开始调用start方法,方法也是调用Catalina类当中的start方法来启动Tomcat

    public void start()
      {
        if (getServer() == null) {
          load();
        }
        
        if (getServer() == null) {
          log.fatal("Cannot start server. Server instance is not configured.");
          return;
        }
        
        long t1 = System.nanoTime();
        
        try
        {
          getServer().start();
        } catch (LifecycleException e) {
          log.error("Catalina.start: ", e);
        }
        
        long t2 = System.nanoTime();
        if (log.isInfoEnabled()) {
          log.info("Server startup in " + (t2 - t1) / 1000000L + " ms");
        }
        
        if (this.useShutdownHook) {
          if (this.shutdownHook == null) {
            this.shutdownHook = new CatalinaShutdownHook();
          }
          Runtime.getRuntime().addShutdownHook(this.shutdownHook);
          
          LogManager logManager = LogManager.getLogManager();
          if ((logManager instanceof ClassLoaderLogManager)) {
            ((ClassLoaderLogManager)logManager).setUseShutdownHook(false);
          }
        }
        
        if (this.await) {
          await();
          stop();
        }
      }
    

    看到调用的还是StandardServer类的start方法来启动Tomcat容器

    看到类似于init的方式,我们看到也是通过调用org.apache.catalina.util.LifeCycleBase类的start方法调用一系列的startInternal方法来启动的

    public final synchronized void start()
        throws LifecycleException
      {
        if ((LifecycleState.STARTING_PREP.equals(this.state)) || (LifecycleState.STARTING.equals(this.state)) || (LifecycleState.STARTED.equals(this.state)))
        {
          if (log.isDebugEnabled()) {
            Exception e = new LifecycleException();
            log.debug(sm.getString("lifecycleBase.alreadyStarted", new Object[] { toString() }), e);
          }
          else if (log.isInfoEnabled()) {
            log.info(sm.getString("lifecycleBase.alreadyStarted", new Object[] { toString() }));
          }
          
          return;
        }
        
        if (this.state.equals(LifecycleState.NEW)) {
          init();
        } else if (this.state.equals(LifecycleState.FAILED)) {
          stop();
        } else if ((!this.state.equals(LifecycleState.INITIALIZED)) && (!this.state.equals(LifecycleState.STOPPED)))
        {
          invalidTransition("before_start");
        }
        
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
        try
        {
          startInternal();
        } catch (Throwable t) {
          ExceptionUtils.handleThrowable(t);
          setStateInternal(LifecycleState.FAILED, null, false);
          throw new LifecycleException(sm.getString("lifecycleBase.startFail", new Object[] { toString() }), t);
        }
        
        if ((this.state.equals(LifecycleState.FAILED)) || (this.state.equals(LifecycleState.MUST_STOP)))
        {
          stop();
        }
        else
        {
          if (!this.state.equals(LifecycleState.STARTING)) {
            invalidTransition("after_start");
          }
          
          setStateInternal(LifecycleState.STARTED, null, false);
        }
      }
    

      

  • 相关阅读:
    让SVN自动更新代码注释中的版本号
    eclipse 查看jdk的源代码
    Java Abstract class and Interface
    Eclipse在保存的时间格式化
    Java中使用Runtime和Process类运行外部程序
    免费的东西:火箭的社会图标
    最土团购程序一些常见的数据库操作
    PostgreSQL在何处处理 sql查询之四十五
    遇到 dereferencing pointer to incomplete type 该怎么办
    PostgreSQL在何处处理 sql查询之四十四
  • 原文地址:https://www.cnblogs.com/wuxinliulei/p/5158523.html
Copyright © 2020-2023  润新知