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. Centos Samba 服务器 iptables 和 SElinux 设置

    1.安装samba服务器 # yum install samba 2.配置 # vi /etc/samba/smb.conf security = user (100行左右) 在Share Defin ...

  2. sqlserver 锁与阻塞

    DDL/索引重建 会申请 Sch-M锁 with (nolock) 会申请 Sch-S锁 with (nolock)会阻塞 sch-M, 同样Sch-M也会 阻塞with (nolock) 索引重建2 ...

  3. response.write();改变页面布局的原因及解法

    Response.Write ,在ASP.NET 中不要随便使用 Response.Write,其原因是它会打乱 ASP.NET 的输出流顺序,在aspx.cs 中使用 Response.Write ...

  4. vue.js 渲染完成回调

    vue.js渲染完成后,想触发一些事情,写在哪里呢? 答案是mounted 例子: new Vue({ el:'#demo', data:{ text:'Hello' }, mounted:funct ...

  5. linux sed

    sed 命令 sed -i 's/3306/3308/g' my.cnf mysql # 同时替换两个文件

  6. HDU 3605:Escape(最大流+状态压缩)

    http://acm.hdu.edu.cn/showproblem.php?pid=3605 题意:有n个人要去到m个星球上,这n个人每个人对m个星球有一个选择,即愿不愿意去,"Y" ...

  7. 阿里巴巴矢量图标的使用Demo

    一.html网页的使用步骤: 1. 登录进入阿里巴巴矢量图标库中,选择自己喜欢的图标,放到购物车,http://www.iconfont.cn/plus/manage/index?manage_typ ...

  8. 《编写可维护的JavaScript》——JavaScript编码规范(七)

    UI层的松耦合 在web开发中,用户界面(UI)是由三个彼此隔离又相互作用的层定义的. HTML用来定义页面的数据和语义. CSS用来给页面添加样式,创建视觉特征. JavaScript用来给页面添加 ...

  9. 立即执行函数: (function(){...})() 与 (function(){...}()) 有什么区别?

    没有区别. function foo() {...} // 这是定义,Declaration:定义只是让解释器知道其存在,但是不会运行. foo(); // 这是语句,Statement:解释器遇到语 ...

  10. Mac环境下JDK安装方法

    1.版本 MAC OS 10.10.3 JDK:jdk1.8.0_40 jdk下载mac版本的:http://www.oracle.com/technetwork/java/javase/downlo ...