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);
    }
  }

  

posted @ 2016-01-25 19:35  无心流泪  阅读(565)  评论(0编辑  收藏  举报