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. 基于MDK的mbed工程建立

    个人更喜欢mdk作为IDE来编写代码,而mbed作为一个开源项目,有大量优秀代码可以借鉴使用,今后一段时间都会主要看mbed平台的代码以及国内ebox平台代码         1  首先登陆mbed在 ...

  2. ExtJS6 TreePanel树节点合上展开显示不同图标

    TreePanel的节点如包含子节点,可在展开/合上时显示不同的图标,增强客户端效果,提高用户体验.非常简单,使用TreePanel的两个事件:beforeitemexpand和beforeitemc ...

  3. 一周试用yii开发一个带各种该有功能的web程序(二)

    上篇随笔写完的是yii能使用简单的命令创建出一个基本的架构,我们只需要在这个架构上进行代码编写,扩展功能.而生成的一个小型系统是可以操作的,但是不是我们想要的,所以,这篇结合源码讲如何创建出我们自己的 ...

  4. postman插件安装教程

    第一步: 第二步: 第三步: 这样就可以了. 插件下载链接: http://pan.baidu.com/s/1eRVLMpk 密码: 49vb

  5. YUV格式分析

    转自:http://www.cnblogs.com/armlinux/archive/2012/02/15/2396763.html Andrew Huang <bluedrum@163.com ...

  6. javascript高级程序设计第5章,引用类型

    object类型: 创建object实列的方式有两种,一种是new()方法,一种是对象字面量表示法: 第一种法方:  var obj = new object(); obj.name = 'name' ...

  7. 零配置简单搭建SpringMVC 项目

    SpringMVC是比较常用的JavaWeb框架,非常轻便强悍,能简化Web开发,大大提高开发效率,在各种Web程序中广泛应用.本文采用Java Config的方式搭建SpringMVC项目,并对Sp ...

  8. UI控件封装一般步骤

    封装 如果一个view内部的子控件比较多,一般会考虑自定义一个view,把它内部的子控件的创建屏蔽起来,不让外界关心 外界可以传入对应的模型数据给view,view拿到模型数据后给内部的子控件设置对应 ...

  9. msys2安装

    最近在研究编译linux下的软件到windows环境中. 发现了一个比cygwin更好玩的东西,那就是msys2 其实之前也在试玩mingw和mingw64,2016-08-12,当时的最新版本,mi ...

  10. UVALive 3177 长城守卫

    https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_probl ...