Tomcat源码笔记(五)Connector

58 篇文章 0 订阅
8 篇文章 1 订阅

读到Tomcat源码的Connector模块了,网络IO方面,有几个关键词不懂,大致了解了下

目录

AJP

APR

TLS/SSL/ALPN/JSSE/Tomcat配置https访问

Connector类

new Connector()

Connector.initInternal

Connector.startInternal


AJP

Apache JServ Protocol,一种二进制传输协议

一般用于apache或nginx WEB服务器和Tomcat之间的通信协议。动静分离的时候使用,配置apache代理示例如下(httpd-vhosts.conf详细配置百度),访问动态资源时,由apache web服务器将请求以AJP协议发送给Tomcat的AJP端口,Tomcat支持AJP的协议解析,解析后和http请求一样,寻找servlet来处理请求。因为AJP是二进制传输比起http更精简,效率也更高些

APR

Apache portable Run-time libraries,Apache可移植运行库),和BIO、NIO一样都是Tomcat支持的IO模式,server.xml如下配置,并需要下载相应的库文件(windows下下载tcnative-1.dll,放到$JAVA_HOME/bin下,百度知)

具体比之NIO好多少我没有进行测试,暂时只是扫我的盲所以不深究,网上一篇的博客写道:Tomcat使用APR将以JNI的形式调用Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高Tomcat对静态文件的处理性能。 Tomcat apr也是在Tomcat上运行高并发应用的首选模式。

    <Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
              connectionTimeout="20000"
               redirectPort="8443" />

TLS/SSL/ALPN/JSSE/Tomcat配置https访问

写到一半发现偏题太严重了,一时半会还真写不清楚

另起一篇:TCP、TLS\SSL、JSSE、HTTPS杂烩分析

Connector类

大致先看看Connector类中干了什么,Catalina.createStartDigester()中可以看到server.xml的标签结构,也就是tomcat的组件层次结构,(本文Tomcat8.5)代码截图如下,也就是说,Connector下还有SSLHostConfig、Certificate,OpenSSLConf等组件,顾名思义是对TLS/SSL层的配置,当前先抛开这些不看,我想先把一般流程先捋完。 

new Connector()

在Catalina类中解析server.xml时调用ConnectorCreateRule创建新Connector对象

创建协议处理器类,用于接收socket连接和处理socket报文,不同的协议解析方式自然是不一样的,这里支持两种协议(HTTP/AJP)和两种IO方式(NIO/APR),BIO方式在8.5版本已经被声明@Deprecated

public class Connector extends LifecycleMBeanBase  {
    protected static final HashMap<String,String> replacements = new HashMap<>();
    static {
        replacements.put("acceptCount", "backlog");
        replacements.put("connectionLinger", "soLinger");
        replacements.put("connectionTimeout", "soTimeout");
        replacements.put("rootFile", "rootfile");
    }

   public Connector(String protocol) {
        // 看下方代码,即设置当前connector的io方式和协议处理类
        // 当前只关注Http11NioProtocol
        setProtocol(protocol);
        // Instantiate protocol handler
        ProtocolHandler p = null;
        try {
            Class<?> clazz = Class.forName(protocolHandlerClassName);
            p = (ProtocolHandler) clazz.getConstructor().newInstance();
        } catch (Exception e) {
            log.error(sm.getString(
                    "coyoteConnector.protocolHandlerInstantiationFailed"), e);
        } finally {
            this.protocolHandler = p;
        }

         // 默认false, UTF8
        if (Globals.STRICT_SERVLET_COMPLIANCE) {
            uriCharset = StandardCharsets.ISO_8859_1;
        } else {
            uriCharset = StandardCharsets.UTF_8;
        }
    }

   public void setProtocol(String protocol) {

        boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
                AprLifecycleListener.getUseAprConnector();

        if ("HTTP/1.1".equals(protocol) || protocol == null) {
            if (aprConnector) {
                setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
            } else {
                setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
            }
        } else if ("AJP/1.3".equals(protocol)) {
            if (aprConnector) {
                setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
            } else {
                setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
            }
        } else {
            setProtocolHandlerClassName(protocol);
        }
    }
}

 在XML解析的时候调用各属性的set方法,将各种属性反射设置到ProtocolHandler对象中,端口,最大连接数,超时时间等

    public void setPort(int port) {
        this.port = port;
        setProperty("port", String.valueOf(port));
    }

    public boolean setProperty(String name, String value) {
        String repl = name;
        if (replacements.get(name) != null) {
            repl = replacements.get(name);
        }
        return IntrospectionUtils.setProperty(protocolHandler, repl, value);
    }

Connector.initInternal

1、初始化CoyoteAdapter并设置到协议处理器中

2、初始化具体的协议处理器Http11NioProtocol

CoyoteAdapter是协议处理器和Engine的中间层的一个组件,ProtocolHandler接收到socket请求并解析,最后调用CoyoteAdapter来处理,CoyoteAdapter中查找Engine中匹配请求的具体某个应用的Servlet,找到则交给Engine处理,否则404返回

   @Override
    protected void initInternal() throws LifecycleException {
        // 注册 MBean
        super.initInternal();

        // Initialize adapter
        adapter = new CoyoteAdapter(this);
        protocolHandler.setAdapter(adapter);

        // Make sure parseBodyMethodsSet has a default
        if (null == parseBodyMethodsSet) {
            // 设置需要解析请求体的HTTP方法类型,默认POST
            setParseBodyMethods(getParseBodyMethods());
        }

        if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
            throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoApr",
                    getProtocolHandlerClassName()));
        }
        if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
                protocolHandler instanceof AbstractHttp11JsseProtocol) {
            // apr模式且启用openssl加密,设置一些属性
            AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
                    (AbstractHttp11JsseProtocol<?>) protocolHandler;
            if (jsseProtocolHandler.isSSLEnabled() &&
                    jsseProtocolHandler.getSslImplementationName() == null) {
                // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
                jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
            }
        }

        try {
            protocolHandler.init();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
        }
    }

Connector.startInternal

ProtocolHandler的启动start

   protected void startInternal() throws LifecycleException {

        // Validate settings before starting
        if (getPort() < 0) {
            throw new LifecycleException(sm.getString(
                    "coyoteConnector.invalidPort", Integer.valueOf(getPort())));
        }

        setState(LifecycleState.STARTING);

        try {
            protocolHandler.start();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
        }
    }

也就是Connector其真正的操作都是依靠protocolHandler实现,而协议处理器ProtocolHandler又基本上依赖组件Endpoint实现,详细看下节

Tomcat源码笔记(六)Connector--Endpoint​​​​​​​

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值