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. Windows内核开发中如何区分文件对象究竟是文件还是文件夹?

    今天有同行问了一个问题,Windows文件过滤驱动里的如何去区分一个对象是文件还是文件夹?我花了1小时左右翻阅了一些微软的文档以及以前的遗留代码,发现在WDK的帮助文档中是这么定义的: FILE_OB ...

  2. YbSoftwareFactory 代码生成插件【二十五】:Razor视图中以全局方式调用后台方法输出页面代码的三种方法

    上一篇介绍了 MVC中实现动态自定义路由 的实现,本篇将介绍Razor视图中以全局方式调用后台方法输出页面代码的三种方法. 框架最新的升级实现了一个页面部件功能,其实就是通过后台方法查询数据库内容,把 ...

  3. 卓越精Forsk.Atoll.v3.3.2.10366无线网络

    卓越精Forsk.Atoll.v3.3.2.10366无线网络 Atoll是法国 FORSK 公司开发的,是一个全面的.基于Windows的.支持2G.3G.4G多种技术,用户界面 友好的无线网络规划 ...

  4. input失去隐藏光标(移动端)

    <input type="text" readonly name='lbinput' onfocus="lbinput.blur()">

  5. java 使用jar包

    //主类 路径 /home/fly/flywww/c/java import mypackage.One; import mypackage.Two; public class Test { publ ...

  6. 用hexdump获取event的输出信息

    当我们在调试输入设备时,如:键盘,触摸屏 会使用到hexdump工具.其内容如下: 1. 键盘: # cat /dev/input/event0 | hexdump 0000000 f6a6 4e15 ...

  7. noi 6047 分蛋糕

    题目链接:http://noi.openjudge.cn/ch0405/6047/ 和Uva1629很类似,不过,可能用记忆化难写一点,状态初始化懒得搞了.就用循环好了. 状态描叙也可以修改,那个题目 ...

  8. android 命令行

    android create avd --target --name cupcake 建立模拟器:           $ android create avd --target 2 --name c ...

  9. Maven安装配置使用

    Maven介绍 Maven是一个项目管理工具,它包含了一个项目对象模型 (Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理 ...

  10. oracle 锁表问题

    oracle执行表数据更新的时候,会遇到锁表问题,比方说,会遇到这样的问题,主要原因是这张表被其他人占用,修改数据没有提交.oracle为了避免脏数据的产生,在其安全机制下,锁住该表. 执行如下操作, ...