Tomcat源码阅读之StandardEngine分析与Valve的设计

本文深入探讨Tomcat的StandardEngine组件,解析其如何管理Container和Connector对象,以及Engine与Valve的关系。Valve作为请求处理链路的核心,其接口设计包含一个处理请求的invoke方法和应对Comet事件的event方法。Engine继承Container接口,并通过addChild方法确保仅能添加Host对象。StandardEngine在构造时会设置基本Valve为StandardEngineValve,其invoke方法主要负责将请求转发给对应Host的Pipeline处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇的文章中看了StandardService的实现。。。这里可以将它要做的事情总结如下:

(1)管理其拥有的container对象,以及其拥有的connector对象,同时service只能有一个container对象,可以拥有多个connector对象。。。

(2)StandardService对象同时还要处理request的map问题,它有maplistener和mapper,maplistener用于监听container对象,从而增加mapper里面的信息。。。


上面说service只能有一个Container对象,这个container对象其实一般就是Engine对象,而Engine对象一般都是使用StandardEngine的。。。但是在具体的分析StandardEngine之前呢,先来看看Valve的设计。。。

在以前分析Container的时候提到过,每个container对象都有一个pipeline对象用于处理请求,而pipeline其实则是一个valve的链表,它是用valve对象来具体的处理请求的。。。

这里就先来看看valve接口的设计吧:

//value对象是与container相关联的处理请求的组件,一系列的value组成了pipeline
public interface Valve {

    public Valve getNext();  //返回pipeline的下一个value对象,在pipeline上面,valve对象组成了一个链表

    public void setNext(Valve valve);  //设置下一个value对象

    //执行一些周期的工作
    public void backgroundProcess();

    //处理request与response
    public void invoke(Request request, Response response)
        throws IOException, ServletException;

    //处理comet事件
    public void event(Request request, Response response, CometEvent event)
        throws IOException, ServletException;


    //是否支持异步
    public boolean isAsyncSupported();


}

接口的设计应该蛮简的,从getNext和setNext两个方法的名字就知道valve对象构成了一个链表。。。

这里还有一个invoke方法用于处理具体的http请求。。。。当然还有个event方法用于响应comet事件。。。。


好啦,大概知道valve是干嘛的了,接下来就来看看Engine吧,先来看看它的接口的定义吧:

public interface Engine extends Container {

    public String getDefaultHost();  //返回当前host用的默认host名字

    public void setDefaultHost(String defaultHost);   //设置host名字

    public String getJvmRoute();   //

    public void setJvmRoute(String jvmRouteId);  //jvm的routeid

    public Service getService();   //返回当前engine关联的service

    public void setService(Service service);   //设置当前关联的service


}

这里可以看到继承了Container接口。。。方法还是挺少的。。。这里DefaultHost是用于配置当前engine对象默认使用的host对象。。。因为在engine中可以定义多个host,通过名字来指定一个默认的host。。。

好啦,接下来就来看看StandardEngine的实现吧,它首先继承了ContainerBase,那么可以进行container以及pipeline的管理。。然后当然还有实现engine接口了。。。

来看看它的构造方法吧:

    public StandardEngine() {

        super();
        pipeline.setBasic(new StandardEngineValve());   //这里会设置pipeline的basic
        /* Set the jmvRoute using the system property jvmRoute */
        try {
            setJvmRoute(System.getProperty("jvmRoute"));   //这个是集群用的吧
        } catch(Exception ex) {
            log.warn(sm.getString("standardEngine.jvmRouteFail"));
        }
        // By default, the engine will hold the reloading thread
        backgroundProcessorDelay = 10;   //后台处理延迟10

    }

这里主要要做的事情就是在pipeline上面添加一个basic的valve吧。。。然后jvmroute用于集群的,这个就暂时不看了。。


再来看看它的一些属性的定义吧:

    private String defaultHost = null;  //当前engine对象用的默认的host的名字

    private Service service = null;  //所属的service对象

    private String jvmRouteId;

这个也没啥意思吧,具体的干嘛用的注释也说了。。。。

另外来看看这里的addChild方法:

    //这里只能加入host
    public void addChild(Container child) {  //添加child

        if (!(child instanceof Host))
            throw new IllegalArgumentException
                (sm.getString("standardEngine.notHost"));
        super.addChild(child);

    }

嗯,engine对象的child只能是host对象。。。

另外再来看看setParent方法:

    //设置父container,engine对象是最上层的container对象了,所以它没有添加parent的方法
    public void setParent(Container container) {

        throw new IllegalArgumentException
            (sm.getString("standardEngine.notParent"));

    }

可以知道engine对象是最顶层的container对象。。。。。


这里再来看看在catalina的createStartDigester方法中的一段代码。。这个是用于通过解析server.xml文件来创建server对象的部分。。。

 digester.addRule("Server/Service/Engine",
                         new SetParentClassLoaderRule(parentClassLoader));  //如果有发现engine,那么设置container(Engine对象)的parentClassloader,shareloader

通过这段代码是想提醒一下,engine对象在创建的时候会将parentClassLoader设置为sharLoader。。。


好啦,最后我们在StandardEngine的构造函数中看到设置了pipeline对象的basic的valve为StandardEngineValve对象。。。那么就来看看它的invoke方法就好啦吧:

    @Override
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {

        // Select the Host to be used for this Request
        Host host = request.getHost();   //获取这个请求所map的host对象
        if (host == null) {   //若果没有的话,那就可以说出错了
            response.sendError
                (HttpServletResponse.SC_BAD_REQUEST,
                 sm.getString("standardEngine.noHost",
                              request.getServerName()));
            return;
        }
        if (request.isAsyncSupported()) {  //根据host的pipeline对象来设置当前是否支持异步
            request.setAsyncSupported(host.getPipeline().isAsyncSupported());
        }

        // Ask this Host to process this request
        host.getPipeline().getFirst().invoke(request, response);  //调用host对象的pipeline来处理这个请求

    }

感觉这里没做太多的事情吧,主要是获取当前request的所map到的host对象,然后调用host对象的pipeline来处理就好了。。。


那么到这里StandardEngine就差不多吧,感觉要做的事情不多。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值