APR连接器的思路和bio,nio的整体架构也是类似的,可以看到下面的整体框图:
第一个区别是,对于从Acceptor线程中的socket解析这块,无论是nio还是bio都是在Acceptor线程内直接阻塞执行的,对于APR通道,搞出一个SocketWithOptions的线程,专门执行这个socket解析的工作,然后直接交给Poller线程进行poll;
其次,SSL交互和socket接收等等都是调用tomcat-native的JNI的代码来完成的。
下面通过源码分析,讲讲整个框图中比较核心的部分。

0.LifecycleListener
对于LifecycleListener来说,每一个安插在Tomcat的组件,只要实现了Lifecycle和LifecycleListener都会有生命周期事件,当组件在tomcat进行启动,停止都会出发Lifecycle事件,然后调用对应的LifecycleListener方法,我们以一个例子:
a.自定义监听类,代码打成任意名的jar包放到Tomcat/lib下
package com.test.listener;
import org.apache.catalina.*;
public class MyListener implements LifecycleListener{ 
    public void lifecycleEvent(LifecycleEvent event) {  
        System.out.println("组件类型:"+event.getLifecycle());  
        System.out.println("生命周期阶段 : "+event.getType()); 
       }
    } 

b.配置Tomcat/conf/server.xml,
加上一句 <Listener className="com.test.listener.MyListener" /> 

c.运行Tomcat,Console上得到System.out.print输出

组件类型:StandardServer[8005]
生命周期阶段 : before_init
组件类型:StandardServer[8005]
生命周期阶段 : after_init
组件类型:StandardServer[8005]
生命周期阶段 : before_start
组件类型:StandardServer[8005]
生命周期阶段 : configure_start
组件类型:StandardServer[8005]
生命周期阶段 : start
组件类型:StandardServer[8005]
生命周期阶段 : after_start
.....

上述的这些事件,就是Tomcat中各组件的触发的事件:
before_init ,after_init 之间会触发组件的 initinternal,会做一些加载资源,库等一些准备工作;
configure_start 是配置属性设置到组件中事件;
start,after_start之间会调用组件的starttinternal,进行组件的真正的加载工作;
这个是启动的时候的相关的事件,停止,销毁也有对应的事件和上述的过程是对应的;
我们可以从日志中就可以通过这些事件来查看,tomcat中运行的各个组件究竟是哪一些组件处于什么状态;

1.AprLifecycleListener
对于APR通道来将,需要在server.xml中配置一个LifecycleListener:

这也就意味着,在APR通道启动的时候,APR组件需要加载一些内容,主要的内容就是tomcat-native需要依赖的库。
对于Listener继承了LifecycleListener接口之后,要实现其lifecycleEvent方法,这些方法就是上一小节中的几个生命周期事件。
从代码中可以分析出来,当组件init之前,首先进行init初始化加载native的库,然后基于apr和openssl是否加载,来启动SSL的配置;
在组件销毁之后,卸载掉native库,以免占用操作系统的资源。
首先看看init方法:
对于init方法,通过Library类的来加载native的资源,传递APR的一些参数进去。
第二步是initialize方法,这个initialize主要是启动openssl:
调用的方式是通过tomcat-native的SSL类,这个SSL类方法都是native的,其通过c去直接启动opensslEngine;
除此之外,可以看到对于tomcat-native主页中提到的美国的FIPS安全认证,tomcat在这块也提供了支持。

2.Http11AprProtocol

Http11AprProtocol是APR通道的http协议实现的总控,这个类和NIO,BIO通道一样,持有Endpoint和Handler:
其次,对于Apr通道的各个属性,这个Http11AprProtocol 仅仅起到了代理的作用:

其最终的属性都会设置到APREndpoint中去,然后在通道启动的时候,将这些属性分发到逻辑中。

3.AprEndpoint
APREndpoint是APR通道的主要实现类,负责几个线程池启动,socket属性处理,按照惯例我们还是看看其bind(初始化),start(启动)两个过程。
bind方法中一般是启动ServerSocket绑定,而对于APR来讲,其socket直接就是操作系统的socket,走的是JNI的流程:

基于APR的实现逻辑,首先调用APR的memory pool,然后创建APR的serversocket池,最后再通过serversocket池创建serversocket;
上述的三个调用都是系统调用,也就是都是通过JNI对不同操作系统的socket生成。
其次,bind方法中同样对SSL启动也进行调用,这里调用最终会将APR通道配置的SSL参数都配置到openssl中:

SSLContext.make实际上是也是native方法,通过openssl调用其内部的SSLContext的生成,这里的sslcontext仅仅是一个返回值,标识此次调用是否成功;
其余的操作,都是将APR的SSL属性设置到openssl中去,也是采用这种JNI调用:


4.Acceptor/Poller/SocketProcessor
bind方法是做初始化,在start启动的时候,会将APREndpoint的几个线程池启动:

从上面的start代码可以看到5类线程。

首先来看一下Acceptor线程主要的作用接收socket请求,同样也是系统调用:

但是在APR通道中,因为socket设置属性需要调用系统调用,也就是JNI的代码,
因此为了防止这块的性能的损失,单独做出一个线程对于socket的options的处理,也就是SocketOptionsProcessor:

将socket包装成AprSocketWrapper,传入到SocketOptionsPorcessor中;
SocketOptionsPorcessor线程使用的是工作线程池,这个需要注意;

SocketOptionsPorcessor线程中,将socket属性设置完,加入到addList中,传递给Poller线程进行socket;
Poller线程主要维护的是socket的read和write,Acceptor线程当socket进来以后,后续的读写都委托给poller来做了;
Poller线程中还有关于comet,socket的进一步包装处理,也有关于pollertimeout的超时控制,将这些处理完,其余的都交给SocketPorcessor;
其余的流程就是和其它通道比较类似了,这里就不再缀余了。

总结:
可以总结一下:APR通道无论是socket创建,还是SSL引擎启动等等这些都是采用JNI的代码调用底层的系统调用来完成的,因为调用系统调用次数,所以对于整个
APR调用链条中,系统调用比较多的部分,多采用一个线程来异步的做这些事,这样可以提升整体的效率。


j.APR连接器整体框图(含SSL实现分析)的更多相关文章

  1. b.BIO连接器整体框图

    上一讲讲解过NIO的框图,可以看来,NIO通道是目前Tomcat7以后的默认的通道的推荐配置,在Tomcat6和以前的配置中,BIO是主流的配置: 只需要修改protocol协议部分即可,而后续还有A ...

  2. J.U.C 整体认识

    深入浅出 Java Concurrency (1) : J.U.C的整体认识 去年年底有一个Guice的研究计划,可惜由于工作“繁忙”加上实际工作中没有用上导致“无疾而终”,最终只是完成了Guice的 ...

  3. 基于Hi3559AV100的视频采集(VDEC-VPSS-VO)整体框图设计

    下面给出基于Hi3559AV100的视频采集整体设计,具体设计将在后续给出: 图形采集端整体设计 Hi3559AV100软件程序按结构划分可分为4层,第一层是硬件驱动层,第二层是操作系统层,第三层是媒 ...

  4. 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析

    前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获 ...

  5. MongoDB的SSL实现分析

    1. OPENSSL接口封装 MongoDB封装了OPENSSL的SSL通信接口,代码在mongo/util/net目录.主要包括以下几个方面: 1) SSL配置参数,在ssl_options(.cp ...

  6. LeetCode (85): Maximal Rectangle [含84题分析]

    链接: https://leetcode.com/problems/maximal-rectangle/ [描述] Given a 2D binary matrix filled with '0's ...

  7. SSL原理分析

    SSL协议的工作流程: 服务器认证阶段:       1)客户端向服务器发送一个开始信息“Hello”以便开始一个新的会话连接:      2)服务器根据客户的信息确定是否需要生成新的主密钥,如需要则 ...

  8. TiDB 整体架构 结合yarn zookeeper分析架构

    TiDB 简介与整体架构| PingCAP https://www.pingcap.com/docs-cn/overview/ 真正金融级高可用 相比于传统主从 (M-S) 复制方案,基于 Raft ...

  9. jQuery使用():Callbacks回调函数列表之异步编程(含源码分析)

    Callbacks的基本功能回调函数缓存与调用 特定需求模式的Callbacks Callbacks的模拟源码 一.Callbacks的基本功能回调函数缓存与调用 Callbacks即回调函数集合,在 ...

随机推荐

  1. ThinkPHP 下如何隐藏index.php

    最近一直在做孕妈团的项目,因为部署到实际项目中出现了链接打不开的情况,要默认添加index.php才能正常访问. 当时忘了是Tinkphp的URL重写模式:以后遇到相同问题,首先要想到URL重写模式. ...

  2. 富文本编辑器TInyMCE,本地图片上传(Image Upload)

    TinyMCE 官网 (类似:百度的富文本web编辑器UEditor) 第一步 下载 TinyMCE,解压后放入工程,在需要的HTML页面引入tinymce.min.js. 第二步 下载tinyMCE ...

  3. python :模态对话框

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  4. python 列表排序

    转自http://www.iplaypython.com/jinjie/jj114.html reverse()方法 将列表中元素反转排序,比如下面这样>>> x = [1,5,2, ...

  5. 数据持久化以及DAO模式的简单使用

    持久化:(是将程序中的数据在瞬时状态和持久状态间转换机制)        即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘).持久化的主要应用是将内存中的对象存储在关系型的数据库中,当然 ...

  6. android 获取设备拔插状态广播事件易漏掉的一行属性!

    我们都知道设备拔插的状态获取需要一个权限   <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILES ...

  7. YTU 3026: 中序线索化二叉树

    原文链接:https://www.dreamwings.cn/ytu3026/2896.html 3026: 中序线索化二叉树 时间限制: 1 Sec  内存限制: 128 MB 提交: 9  解决: ...

  8. 财务报表 > 现金流表的直接法,间接法,Cash Flow from Operating Activites

    经营活动现金流量 Cash Flow from Operating Activites 是指企业投资活动和筹资活动以外的所有的交易和事项产生的现金流量.它是企业现金的主要来源. 1. 直接法经营活动现 ...

  9. mysql 自动备份和nginx自动安装脚本

    一.自动备份Mysql脚本: 如下脚本为mysql自动备份脚本,仅供参考,可以根据实际情况修改. #!/bin/sh #auto backup mysql #wugk #Define PATH定义变量 ...

  10. linux开启telnet

    windows客户端如果通过cmd窗口连接到远程linux服务器,可以使用telnet: centos系统默认telnet 23端口是关闭的. 服务器本地使用nmap ip地址 -p 23 查看tel ...