博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Jetty : Embedded Server 启动流程 - 1
阅读量:5919 次
发布时间:2019-06-19

本文共 7855 字,大约阅读时间需要 26 分钟。

前言

本文基于 Jetty 8.1.x 版本简单介绍 Jetty Embedded Server 核心概念,线程模型,启动流程。以下代码片段摘自 Jetty 源代码 中的 example-jetty-embedded 模块的 OneServletContext.java

public class OneServletContext {    public static void main(String[] args) throws Exception {        Server server = new Server(8080);        ServletContextHandler context = new ServletContextHandler(        ServletContextHandler.SESSIONS);        context.setContextPath("/");        server.setHandler(context);        ...                // Serve some hello world servlets        context.addServlet(new ServletHolder(new HelloServlet()),"/*");        context.addServlet(new ServletHolder(                new HelloServlet("Buongiorno Mondo")),"/it/*");        context.addServlet(new ServletHolder(                new HelloServlet("Bonjour le Monde")),"/fr/*");        server.start();        server.join();    }}

Embedded Jetty 使用起来很方便,少数几行代码就可以实现一个 http (Servlet)接口

  • 创建 Server 对象,设置要监听的端口 8080
  • 创建 ServletContextHandler 对象,ServletContextHandler "is-a" Handler(Request Handler),提供 ServletContext
  • 将 ServletContextHandler 关联到 Server(即 server.setHandler(context))
  • 向 ServletContextHandler 中添加 Servlet,以 ServletHolder 的形式
  • 启动 Server

核心概念

LifeCycle

The lifecycle(生命周期) interface for generic components,声明 start(启动),stop(停止),isRunning,isStarted(查询状态)等方法

AbstractLifeCycle

实现 LifeCycle 接口的抽象类,提供生命周期管理默认实现:例如通过 _state 属性保存组件状态,提供 start,stop 默认实现

public final void start() throws Exception {    // 线程安全    synchronized (_lock) {        try {            // 状态保护            if (_state == _STARTED || _state == _STARTING) {                return;            }            setStarting();            // 将具体的 start 逻辑推迟到具体的子类实现            doStart();            setStarted();        } catch (...) {            ...        }    }}

AggregateLifeCycle

An AggregateLifeCycle is an LifeCycle implementation for a collection of contained beans

AggregateLifeCycle 继承自 AbstractLifeCycle,管理一组 Bean 的生命周期

public class AggregateLifeCycle extends AbstractLifeCycle implements    Destroyable, Dumpable {    private final List
_beans = new CopyOnWriteArrayList<>(); private boolean _started = false; @Override protected void doStart() throws Exception { for (Bean b: beans) { if (b._managed && b._bean instanceof LifeCycle) { LifeCycle l = (LefeCycle) b._bean; if (!l.isRunning()) { // start managed bean l.start(); } } } _started =true; super.doStart(); }}

Server

类层次

AbstractLifeCycle    AggregateLifeCycle        AbstractHandler            AbstractHandlerContainer                HandlerWrapper                    Server

Server 类是 Jetty 的《门面》类,包含:

  • Connector,接收客户端请求
  • Handler,处理客户端请求
  • ThreadPool,任务调度线程池

通过 Server 类提供的各种 set 属性方法可以定制 Connector, ThreadPool,如果没有特殊指定 Server 类会创建默认实现,比如默认的 Connector 为 SelectChannelConnector,默认的 ThreadPool 为 QueuedThreadPool

Connector

(主要)类层次:

Connector    AbstractConnector        AbstractNIOConnector            SelectChannelConnector

Connector 接口及其实现类用于 接收客户端请求,(HTTP/SPDY)协议解析,最终调用 Server 中的(Request)Handler 处理请求,SelectChannelConnector 是 Server 默认使用的 Connector

public Server(int port) {    setServer(this);    Connector connector = new SelectChannelConnector();    connector.setPort(port);    setConnectors(new Connector[]{ connector });}

Handler

Handler 或者叫作 Request Handler,用于处理客户端请求

public interface Handler extends LifeCycle, Destroyable {    ...    void handle(String target, Request baseRequest, HttpServletRequest request,            HttpServletResponse response);    ...}

handle 方法的签名已经很接近 Servlet service 方法,这里的 target 通常是请求的 uri,用于根据 Servlet 配置规则找到具体的 Servlet 并调用其 service 方法

线程模型

Jetty Server 使用线程池来处理客户端请求,ThreadPool 接口定义了线程池基本操作,Server 默认使用 QueuedThreadPool 类,如果需要,可以通过 Server.setThreadPool 方法手动设置线程池

注:Jetty 9.x 线程模型比较复杂,Jetty 8.x 比较简单,代码好读一些~

QueuedThreadPool

QueuedThreadPool 类层次结构

ThreadPool    SizedThreadPool        QueuedThreadPool

线程池核心问题:

  • 线程管理:包括创建,销毁等
  • 任务分派:推或拉模型

线程管理

通过最小线程个数,最大线程个数,线程最大空闲时间 来动态创建,销毁线程

线程池初始化

// QueuedThreadPool.javapublic class QueuedThreadPool {    // 默认最大线程数    private int _maxThreads = 254;    // 默认最小线程数    private int _minThreads = 8;        ...    @Override    protected void doStart() throws Exception {        ...        int threads = _threadsStarted.get();        // 启动 _minThreads 个线程        while (isRunning() && threads < _minThreads) {            startThread(threads);            threads = _threadStarted.get();        }    }}

线程销毁

当线程空闲时间超过设定的阈值 _maxIdleTimeMs 而且线程池的线程个数高于 _minThreads 时,线程将从 Runnable run 方法中退出

# QueuedThreadPool.javaprivate Runnable _runnable = new Runnable() {    public void run() {        boolean shrink = false;        ...        try {            Runnable job = _jobs.poll()            while (isRunning()) {                // job loop:从队列中拉取 job 并执行直到队列为空                while (job != null && isRunning()) {                    runJob(job);                    job = _jobs.poll();                }                // idle loop                try {                    _threadsIdle.incrementAndGet();                    while (isRunning() && job == null) {                        // 如果 _maxIdleTimeMs < 0 就进入阻塞模式,直到成功拉取到 job                        if (_maxIdleTimeMs <= 0) {                            job = _jobs.take();                        } else {                            final int size = _threadsStarted.get();                            // 如果线程个数少于 _minThreads 那么不需要回收线程                            if (size > _minThreads) {                                long last = _lastShrink.get();                                long now = System.currentTimeMillis();                                if (last == 0 || (now - last) > _maxIdleTimeMs) {                                    shrink = _lastShrink.compareAndSet(last, now) &&                                        _threadsStarted.compareAndSet(size, size - 1);                                    if (shringk) {                                        // 退出 while 循环,即终止线程                                        return;                                    }                                }                            }                            // 带 timeout 的 poll                            job = idleJobPoll();                        }                    }                }            }        } catch (...) {        } finally {        }    }}

任务分派

使用阻塞队列,工作线程从阻塞队列中主动拉取(poll)任务(job),QueuedThreadPool 默认使用 ArrayBlockingQueue,如果需要可以通过构造方法手动指定阻塞队列的具体实现

public class QueuedThreadPool {    public QueuedThreadPool(BlockingQueue
jobQ) { this(); _jobs = jobQ; _jobs.clear(); } public boolean dispatch(Runnable job) { if (isRunning()) { final int jobQ = _jobs.size(); final int idle = getIdleThreads(); // 将 job 放入队列中 if (_jobs.offer(job)) { // 如果当前没有 idle 的线程,或者 队列中堆积的 job 比 idle 线程多那么尝试启动新的线程 if (idle == 0 || jobQ > idle) { int threads = _threadsStarted.get(); if (threads < _maxThreads) { startThread(threads); } } return true; } } return false; }}

启动流程

Server 的启动开始于 start 方法的调用,如上文所述,Server 类继承自 AggregateServer,父类的 start 方法最终调用 Server 的 doStart 方法

Server start

@Overrideprotected void doStart() throws Exception {    ...    // 创建默认的 ThreadPool    if (_threadPool == null) {        setThreadPool(new QueuedThreadPool())    }    try {        super.doStart();    } catch(Throwable e) {...}    // 启动 Connector,接收,处理请求    if (_connectors != null && mex.size == 0) {        for (int i = 0; i < _connectors.length; i++) {            try {                _connectors[i].start();            } catch (Throwable e) {                mex.add(e);            }        }    }    ...}

转载地址:http://cdbvx.baihongyu.com/

你可能感兴趣的文章
Linux系统启动流程详解
查看>>
通过源码解析 Node.js 中一个 HTTP 请求到响应的历程
查看>>
CodeIgniter的密码处理论
查看>>
运营不需要人脉?
查看>>
Spring Cloud Config服务器
查看>>
测试人员必学的软件快速测试方法(二)
查看>>
Agora iOS SDK-快速入门
查看>>
LeetCode | Copy List with Random Pointer
查看>>
引入间接隔离变化(三)
查看>>
统一沟通-技巧-4-让国内域名提供商“提供”SRV记录
查看>>
cocos2d-x 3.0事件机制及用户输入
查看>>
比亚迪速锐F3专用夏季座套 夏天坐垫 四季坐套
查看>>
C++ 数字转换为string类型
查看>>
取证学习资料DVD
查看>>
高性能优化Web前端
查看>>
Sublime Text 格式化代码快捷键
查看>>
疯狂的 Web 应用开源项目
查看>>
程序员全国不同地区,微信(面试 招聘)群。
查看>>
【干货】界面控件DevExtreme视频教程大汇总!
查看>>
用户管理脚本之删除用户——Delete_user.sh
查看>>