从servlet到springboot(15) Tomcat源码分析(2)。Container和connectors

56 篇文章 2 订阅

上一篇中我们分析了tomcat启动的整体流程和管理生命周期的系列组件,这一节,我们将要分析Container和Connectors

先看下Container的类继承体系

可以看到Container有四个子类,Context Engine Wrapper Host和一个默认的实现类 ContainerBase  这些类都继承LifecycleBase接口。所以符合tomcat的生命周期管理方法,上一节也提到过

上面这张图体现了四个子类的关系,Context和Host的区别是Context表示一个应用,比如默认配置下webapps下的每个目录都是一个应用,其中ROOT目录中存放着主应用,其他目录存放着别的子应用,而整个webapps是一个站点。加入www.baidu.com域名对应着webapps目录所代表的站点,其中ROOT目录中就是主应用,访问时直接使用域名即可,而webapps/test目录存放的test子应用,访问时需要用www.baidu.com/test,每一个应用对应一个Context。所有webapps下的应用都属于www.baidu.com的站点。而blog.baidu.com是另一个站点,属于另外一个Host

 

接下去我们来分析下Container的启动过程

前面我们说过service会调用start方法,里面会调用Container和connectors的start和init方法,同样这两个方法内部也是调用模板方法initInternal和startInternal,只是不同的是Container有四个子类的默认实现类,而且Container还有一个默认实现类ContainerBase。

我们先看ContainerBase的initInternal方法

@Override
protected void initInternal() throws LifecycleException {
    BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
    startStopExecutor = new ThreadPoolExecutor(
            getStartStopThreadsInternal(),
            getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
            startStopQueue,
            new StartStopThreadFactory(getName() + "-startStop-"));
    startStopExecutor.allowCoreThreadTimeOut(true);
    super.initInternal();
}

可以看到这主要创建了线程池

再看startInternal方法

@Override
protected synchronized void startInternal() throws LifecycleException {

    // Start our subordinate components, if any
    logger = null;
    getLogger();
    Cluster cluster = getClusterInternal();
    if ((cluster != null) && (cluster instanceof Lifecycle))
        ((Lifecycle) cluster).start();
    Realm realm = getRealmInternal();
    if ((realm != null) && (realm instanceof Lifecycle))
        ((Lifecycle) realm).start();

    // Start our child containers, if any
    Container children[] = findChildren();
    List<Future<Void>> results = new ArrayList<>();
    for (int i = 0; i < children.length; i++) {
        results.add(startStopExecutor.submit(new StartChild(children[i])));
    }

    boolean fail = false;
    for (Future<Void> result : results) {
        try {
            result.get();
        } catch (Exception e) {
            log.error(sm.getString("containerBase.threadedStartFailed"), e);
            fail = true;
        }

    }
    if (fail) {
        throw new LifecycleException(
                sm.getString("containerBase.threadedStartFailed"));
    }

    // Start the Valves in our pipeline (including the basic), if any
    if (pipeline instanceof Lifecycle)
        ((Lifecycle) pipeline).start();


    setState(LifecycleState.STARTING);

    // Start our thread
    threadStart();

}

这里主要做了五件事情:

如果有Cluster和Realm则调用其start方法;

Container children[] = findChildren(); List<Future<Void>> results = new ArrayList<>(); for (int i = 0; i < children.length; i++) { results.add(startStopExecutor.submit(new StartChild(children[i]))); }

这几句代码回找到所有的子容器,然后调用start方法

if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start();这句话会启动管道,关于管道会在下一篇说明

setState(LifecycleState.STARTING); 将生命周期状态设置starting模式

Service最先调用的是最顶曾的容器Engine的init和start方法,默认的Engine实现类是StandardEngine,我们直接看这个类的initInternal和startInternal

protected void initInternal() throws LifecycleException {
    // Ensure that a Realm is present before any attempt is made to start
    // one. This will create the default NullRealm if necessary.
    getRealm();
    super.initInternal();
}


/**
 * Start this component and implement the requirements
 * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
 *
 * @exception LifecycleException if this component detects a fatal error
 *  that prevents this component from being used
 */
@Override
protected synchronized void startInternal() throws LifecycleException {

    // Log our server identification information
    if(log.isInfoEnabled())
        log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());

    // Standard container startup
    super.startInternal();
}

可以看到直接调用ContainerBase中的这两个方法

StandardHost这边就不说了

StandardContext的startInternal

@Override
protected synchronized void startInternal() throws LifecycleException {

。。。。。。。。

        if (ok) {
            if (!listenerStart()) {
                log.error( "Error listenerStart");
                ok = false;
            }
        }

        // Check constraints for uncovered HTTP methods
        // Needs to be after SCIs and listeners as they may programatically
        // change constraints
        if (ok) {
            checkConstraintsForUncoveredMethods(findConstraints());
        }

        。。。。。。
        if (ok) {
            if (!filterStart()) {
                log.error("Error filterStart");
                ok = false;
            }
        }

 。。。。。
        if (ok) {
            loadOnStartup(findChildren());
        }

    // Reinitializing if something went wrong
    if (!ok) {
        setState(LifecycleState.FAILED);
    } else {
        setState(LifecycleState.STARTING);
    }
}

StandardContext的startInternal方法主要读取了web.xml中配置的Linsteners,Filters,以及Servlet的配置信息,然后调用了配置的contextInitialized方法,Filter和配置了load-on-startup的Servlet的init方法

Context和Host一样,都有一个LifecycleListener类型的监听器ContextConfig,都会触发相应的事件。

最后看Standardwrapper

initInternal没有重写

startInternal中

@Override
protected synchronized void startInternal() throws LifecycleException {

    // Send j2ee.state.starting notification
    if (this.getObjectName() != null) {
        Notification notification = new Notification("j2ee.state.starting",
                                                    this.getObjectName(),
                                                    sequenceNumber++);
        broadcaster.sendNotification(notification);
    }

    // Start up this component
    super.startInternal();

    setAvailable(0L);

    // Send j2ee.state.running notification
    if (this.getObjectName() != null) {
        Notification notification =
            new Notification("j2ee.state.running", this.getObjectName(),
                            sequenceNumber++);
        broadcaster.sendNotification(notification);
    }

通过代码我们关注到这里面主要做了三件事情,

1.用broadcaster发送通知

2.调用父类的startInternal

3.调用setAvailable方法让Servlet生效

我们把Container的内容分析完了,接下去分析connectors相关内容

Connectors用于接收请求并将请求封装成Request和Response来具体处理,最底层是通过Socket来进行链接的。Req和Res封装完成后会交给Conatiner,Container交给Servlet,Servlet处理完成之后返还给Connector,最后Connector使用Socket将处理结果返回给客户端。这样整个请求就完成了

Connector中有一非常重要的一个组件ProtocalHandler,而这个组件又由Endpoint Processor Adapter三个组件组成

如下图

Endpoint中又包含Acceptor,Handler和AsyncTimeout两个内部类。Acceptor用于监听请求,AsyncTimeout用于检查异步request超时,Handler用于处理接收到的socket,内部调用Processor进行处理,然后调用Adapter的service方法进行适配,最终交给Container进行处理。

在这一篇幅中我们说过在StandardService中的initInternal中有connetors.init方法,这里会初始化connectors

初始化connectors主要就是初始化protocalHandler

在整个connector中,Endpoint是用来处理TCP/IP协议的,processor是用来处理HTTP协议的。

 

关于container和connectors的分析就到此。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Tomcat 8.5.81的源码文件是指完整的Tomcat 8.5.81版本的源代码文件集合。Tomcat是一个由Apache基金会开发的开源Java Servlet容器,用于实现Java Servlet和JavaServer Pages (JSP)技术。Tomcat 8.5.81是Tomcat 8.5系列的一个特定版本,而8.5系列是Tomcat 8.x版本的一个分支。 Tomcat 8.5.81的源码文件包含了Tomcat服务器的所有实现细节和逻辑。它包括了各个核心组件的源代码,如连接器(Connector)、容器(Container)、Servlet和JSP引擎等。通过阅读这些源码文件,可以深入了解Tomcat服务器是如何处理HTTP请求、解析请求、分发请求到对应的Servlet和JSP等。 源码文件中的每个类都对应着Tomcat服务器的不同功能模块。这些文件包含了Java类和接口的定义、方法的实现以及注释说明等。通过研究源码,可以理解到Tomcat的内部工作原理,并可以根据需要进行定制化或扩展开发。 在Tomcat 8.5.81的源码文件中,可能会涉及到线程池、连接池、请求处理流程、安全机制、Session管理、Web应用程序部署等一系列关键组件和功能。此外,还可以进一步了解Apache的Catalina容器、Jasper引擎、Apr库等的实现细节。 总而言之,Tomcat 8.5.81的源码文件提供了深入了解Tomcat服务器内部实现的机会,可以通过阅读和研究源码,对Tomcat有更全面和深入的认识,并对其进行定制化开发、问题排查和性能优化等方面提供了便利。 ### 回答2: Tomcat 8.5.81的源码文件是用Java编写的,用于构建和运行基于Java Servlet、JavaServer Pages (JSP) 和Java WebSocket 的web应用程序。源码文件包含了Tomcat的核心组件和功能实现。 Tomcat 8.5.81的源码文件主要包括以下几个重要的部分: 1. Connector模块:负责处理与客户端的连接,包括HTTP、HTTPS和AJP协议等。在源码文件中,Connector模块涉及到的类主要包括Connector类、Request类、Response类等。这些类实现了连接的建立、请求的解析和响应的发送等功能。 2. Container模块:负责管理和处理Servlet和JSP等组件,包括请求分发、生命周期管理和会话管理等。在源码文件中,Container模块涉及到的类主要包括Context类、Wrapper类等。这些类实现了Servlet和JSP组件的创建、初始化和处理等功能。 3. Catalina模块:作为Tomcat的核心组件,负责整体的服务器管理和控制。Catalina模块涉及到的源码文件比较复杂,包括了容器的启动、配置加载、线程池管理等。其中,Catalina类、Server类和Service类是Catalina模块的主要组成部分。 此外,Tomcat 8.5.81的源码文件还包括了一些辅助的模块和工具类,如日志模块(使用了Commons Logging框架)、认证模块(实现了基本的用户认证和授权)以及内存缓存模块(用于提高性能)等。 值得注意的是,Tomcat 8.5.81的源码文件是一个庞大的项目,包含了数十万行代码。阅读和理解整个源码需要一定的Java和Web开发经验。为了更好地理解和使用Tomcat,建议先熟悉相关的Servlet和JSP编程,并对Java的网络编程有一定的了解。 ### 回答3: Tomcat 8.5.81 是一个非常流行的 Java Web 服务器,它的源代码文件是编写 Tomcat 运行的核心部分的文件。 Tomcat 的源代码文件包含各种 Java 类和配置文件。其中最重要的文件是 Tomcat 的启动类,例如:Catalina、StandardServer 和 Bootstrap。这些类是整个服务器的入口点,负责初始化和启动服务器。 除了启动类,Tomcat 源码文件还包括了一些核心组件,如连接器(Connectors)、容器(Containers)、Realm 和 Valve 等。连接器负责处理 HTTP 请求和响应,容器用于托管网页和应用程序,Realm 用于管理用户认证和授权,Valve 用于在处理请求和响应时添加额外的处理逻辑。 此外,Tomcat源码文件还包括了一些模块和扩展,用于支持 Tomcat 的各种功能和特性。例如,Catalina 模块提供了 Servlet 容器的实现,NIO 模块提供了高效的非阻塞 I/O 功能,WebSocket 模块支持 WebSocket 技术等等。 总而言之,Tomcat 8.5.81 的源码文件是构成整个 Tomcat Web 服务器的核心组成部分。通过阅读和理解这些源码文件,开发人员可以深入了解 Tomcat 的工作原理,并在需要的时候进行二次开发或自定义扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值