启动tomcat需要依赖什么软件?_面试官:来说说Tomcat的启动过程是什么样子的

1.Tomcat分析

作为一个 Java 资深开发人员,对 Tomcat 那是再熟悉不过了,bin目录、conf目录、webapps目录,对这些目录熟悉的简直不能再熟悉了。一言不合就是一个shutdown.sh,或者来个shutdown.bat,但是你知道你的启动startup.bat,和startup.sh他们的启动过程是什么过程么?接下来我们就开始进入分析吧。

2.Tomcat的整体结构图

这个整体结构图可不是大家想的目录结构图,目录结构图就不给大家展示了,自己去打开你的 Tomcat,里面就有你想看到目录结构图,那么整体结构图是什么样子的呢?

45f21007b0576688add2380a3bc87811.png

给大家解释一下这个图的意思,

  • Server:整个服务器。
  • Service:具体的服务。
  • Connector:提供Socket和request,response的连接。
  • Container:用于封装和管理Servlet,以及具体的处理请求。

这个图就把里面的包含关系说的是明明白白了,为什么这么说呢?因为一个Server中可以存在多个服务,也就是多个Service,而一个Service中可以存在多个Connector,但是只能存在一个Container,是不是就非常的清晰了呢?

3.Tomcat的启动过程

接下来我们就来看看源码里面的启动过程吧,Bootstrap类中的启动过程。

这个类的位置是在tomcat的catalina的包里面,大家看一下主方法也就是所谓的main方法,

  public static void main(String[] args) {        //对象初始化        if (daemon == null) {            Bootstrap bootstrap = new Bootstrap();            try {                bootstrap.init();            } catch (Throwable var3) {                handleThrowable(var3);                var3.printStackTrace();                return;            }            daemon = bootstrap;        } else {            Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);        }        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();                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 {                log.warn("Bootstrap: command "" + command + "" does not exist.");            }        } catch (Throwable var4) {            Throwable t = var4;            if (var4 instanceof InvocationTargetException && var4.getCause() != null) {                t = var4.getCause();            }            handleThrowable(t);            t.printStackTrace();            System.exit(1);        }    }

main方法里面的存在也很简单,先进行init的操作,然后再执行start,也就是说,启动过程中,首先要进行初始化,然后接下来再进行启动,最后阶段在来个stop,这样才算完整嘛。

  • load方法:其实说白了load方法就是根据server.xml文件创建Server并且调用Server的init方法进行初始化。
  • start方法:start方法很直白,启动服务器。
  • stop方法:stop方法同样,停止服务器。

在这里的start方法和stop方法调用的分别就是调用了Server内部的start和stop方法,而这三个方法都是按照图中的层级结构来的,先从Server的load,start,stop,然后Server的start再调用Service的start,而Service的start调用的就是Connector和Container的start方法了,这从外到内的启动,就可以把Tomcat完整的启动起来了。

我们在接下来就继续从外到内的启动开始分析一波。

3.1 Catalina启动过程

上面的启动入口我们已经成功找到了,那么我们就继续来,对象初始化完成后,执行了init的方法

  Bootstrap bootstrap = new Bootstrap();            try {                bootstrap.init();            } catch (Throwable var3) {

就是上面的这个,如果参数为空了,那么就开始调用start了,那么start方法是什么呢?

 public void start() throws Exception {        if (this.catalinaDaemon == null) {            this.init();        }        Method method = this.catalinaDaemon.getClass().getMethod("start", (Class[])null);        method.invoke(this.catalinaDaemon, (Object[])null);    }

上面的start方法就是直接使用invoke的方法映射到了catalinaDaemon,也就是到了Catalina的start的方法上,

而这个Catalina的启动无非也就是调用了同样的方法,setAwait方法,load方法,start方法,

  • setAwait方法:用于设置Server启动完成时,是否进入等待,如果是true,那就等待,如果不是false,那就不进入等待。
  • load方法:创建并且初始化Server,
  • start方法:同样是启动服务器

同样的setAwait方法比较少,阿粉就不给大家看了,无非就是个判断,而load方法一定得看,

if (!this.loaded) {            this.loaded = true;            long t1 = System.nanoTime();                    try {                        inputSource.setByteStream((InputStream)inputStream);                        digester.push(this);                        digester.parse(inputSource);                        break label242;                    } catch (SAXParseException var28) {                        log.warn("Catalina.start using " + this.getConfigFile() + ": " + var28.getMessage());                        return;                    } catch (Exception var29) {                        log.warn("Catalina.start using " + this.getConfigFile() + ": ", var29);                    }                } finally {                    if (inputStream != null) {                        try {                            ((InputStream)inputStream).close();                        } catch (IOException var23) {                            ;                        }                    }                }                return;            } try {    //此处同样调用的Server的init方法,                this.getServer().init();            } catch (LifecycleException var24) {                if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {                    throw new Error(var24);                }                log.error("Catalina.start", var24);            }            long t2 = System.nanoTime();            if (log.isInfoEnabled()) {                log.info("Initialization processed in " + (t2 - t1) / 1000000L + " ms");            }        }

而从这里就开始进入下一步了,Server的启动过程,因为从Catalina里面已经找到了getServer的初始化方法,接下来就是要进行Server的初始化,然后加载,然后启动的过程了。

3.2 Server的启动过程

Server是Tomcat里面的接口,而不是类,那么我们就只能去找实现它的子类来于是就找到了StandardServer extends LifecycleMBeanBase implements Server。

一看有继承,还有实现,那就先看看LifecycleMBeanBase这个被继承的类,于是再次去看了它,

public abstract class LifecycleMBeanBase extends LifecycleBase implements JmxEnabled {

嗯?还有继承?继续往下扒拉,

public abstract class LifecycleBase implements Lifecycle {

终于算是找到了,

91b6624e779acf6d8769be464640047c.png
f8d711eb0b995e08e9e6cd30f1caaf2b.png

一看这init方法和start方法又调用了initInternal()和startInternal(),找来找去又回去了,而我也从这里知道了,模板方法,是有自己的子类具体实现

于是回到了StandardServer自己的init和start方法,

 protected void startInternal() throws LifecycleException {        this.fireLifecycleEvent("configure_start", (Object)null);        this.setState(LifecycleState.STARTING);        this.globalNamingResources.start();        Object var1 = this.servicesLock;        synchronized(this.servicesLock) {            for(int i = 0; i 
41319035fd2db25f6cffdc37b4436f46.png

总得来说就是,StandardServer继承自LifecycleMBeanBase,而LifecycleMBeanBase继承自LifecycleBase,而LifecycleBase类中的模板方法,又让自己的子类去进行具体的实现,但是我们要知道他的Tomcat生命周期中存在这些内容才行。

图中都说了,Server里面有Service,那么一定就有,我们得去找找看,于是阿粉再次去找并且去看它到底是个什么意思,

    public void addService(Service service) {        service.setServer(this);        Object var2 = this.servicesLock;        synchronized(this.servicesLock) {            Service[] results = new Service[this.services.length + 1];            System.arraycopy(this.services, 0, results, 0, this.services.length);            results[this.services.length] = service;            this.services = results;            if (this.getState().isAvailable()) {                try {                    service.start();                } catch (LifecycleException var6) {                    ;                }            }            this.support.firePropertyChange("service", (Object)null, service);        }    }

位置是在Server的接口中出现了增加和删除Service的方法,Server的init方法和start方法循环去调用每个Service的init方法和start方法。

接下来我们看看Service的具体实现,找到StandardService:

  protected void initInternal() throws LifecycleException {        super.initInternal();        if (this.engine != null) {            this.engine.init();        }        Executor[] arr$ = this.findExecutors();        int len$ = arr$.length;        int len$;        for(len$ = 0; len$ 

而在方法中主要调用Executor,mapperListener,executor的init方法。

connector之前已经有了,而这个mapperListener就是Mapper的监听器,用来坚挺container容器的变化。

26c0eb6b483efc13d645d5cedea0e0e9.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值