`
cwqcwq
  • 浏览: 74854 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Jetty7 热部署过程详解

    博客分类:
  • j2ee
阅读更多
读者对象

    对 jetty 比较熟悉,想了解其部署原理的开发人员。


一、预备知识

1、什么是jetty
    官方描述:Jetty是一个100%由Java实现的、开源的HTTP服务器和javax.servlet容器,它不仅仅作为一个独立服务软件(如Tomcat)被使用,而且其优良的组件(Componet)设计、高内聚低耦合、高扩展性等特性使得Jetty非常易于作为嵌入式工具使用。由于Jetty构架优秀、实现优雅,所以它被广泛嵌入的到移动设备、工具、框架(frameworks)、应用程序服务器(Application Server)等等领域。

    从开发人员的视图看jetty,由三部分组成:
    A、start.jar:
一个很独立的jar,43k,包含7个类,主要作用是服务器启动前的准备工作。
    B、lib 下的一组jar
jetty的核心jar,每个jar提供不同的功能,如 jetty-jmx.jar 提供JMX功能,jetty-jndi 提供JNDI支持。
    C、etc 下的一组xml文件
Jetty提供了类似IoC/DI容器,jetty.xml配置文件就是这个容器的配置文件。

2、jetty 的过人之处
    简单、精巧、嵌入式
    最快的Servlet服务器之一
    可以处理上千个并发连接
    基于NIO的 Continuation
    websocket 支持

二、jetty 部署概述

1、部署方式介绍
    jetty 支持文件方式和目录方式。

2、部署过程描述

    先从jetty启动说起,通过 java -jar start.jar 启动之后,start.jar 主要做了如下工作:
    1、解析命令行参数,如 -version ,只是屏幕输出各个jar的版本信息,不会启动服务器
    2、准备所需的配置文件,默认配置文件在 start.ini 中指定,也可以在命令行中指定
    3、设置 classpath,根据 OPTIONS 指定的值,将对应的jar加入到classpath
    4、通过反射调用 start.class 指定的值,以启动服务器,start.class的值在 start.config 中指定,文件位于 start.jar\org\eclipse\jetty\start\start.config
默认的启动类是 org.eclipse.jetty.xml.XmlConfiguration,该类解析xml文件,解析的过程就是服务器启动的过程。
    org.eclipse.jetty.server.Server 实现了 LifeCycle,所以在 解析时,会调用 Server 的生命周期方法,在 Server 的 start 过程中,会设置线程池(ThreadPool)、连接器(Connector),并调用 dependentBeans 中所有 bean 的生命周期方法,其中有一个 bean 就是 DeploymentManager(部署管理器),在文件 jetty-deploy.xml 中定义。

    DeploymentManager 中添加了两个 AppProvider,分别是 ContextProvider 和 WebAppProvider。
    ContextProvider:用于部署/监控 contexts 目录,也可指定目录,通过 monitoredDir 属性指定,里面的文件必须是 xml ,并且 xml 中定义的类必须是 ContextHandler 的子类,一般用来定义一个 WebAppContext 实例,该实例对应一个应用(WAR)WebAppProvider:用于部署/监控 webapp 目录,也可指定目录,通过 monitoredDir 属性指定,里面的文件必须是.war或war目录。
    DeploymentManager 也 extends LifeCycle,在 start 过程中,会 1、添加部署过程监听器;2、调用注册的 AppProvider,部署应用。
    WebAppProvider 的部署:
    1、扫描 webapp 目录,满足条件的添加进 _currentScan(在Scanner中),其规则是:1、是一个标准的WAR目录;2、一个.war文件;3、在 contexts 目录中没有对应的xml文件。
    2、具体的扫描过程由 Scanner 完成,在方法 scan 中,完成扫描、部署动作,之后启动定时器,循环调用 scan ,以实现热更新。
    3、部署过程由 reportAddition 方法触发,在该方法中会触发 Scanner 类中定义的部署监听器,能监听三种状态:文件添加、删除、修改
    4、对于添加(即新增部署一个应用),调用 DeploymentManager 的 addApp 方法,在该方法中触发 requestAppGoal,即 Immediately attempt to go to default lifecycle state。
    5、应用的各种状态在jetty中用有向图来描述,其包括的状态有:starting,deployed,started,stopping,deploying,undeployed,undeploying 等。每种状态都定义的相应的绑定监听器,如 starting 过程定义了 StandardStarter,以负责具体的部署过程。
    6、最后调用 ServletContextHandler 的 startContext 开始部署应用:解析配置,完成 servlet 容器该完成的工作。
ContextProvider 的部署过程类似,它在解析xml过程中产生的 App,其中定义了war的位置,它会根据该war的位置去部署。


三、热部署过程详解

部署所涉及核心类的UML图:




    实际上,jetty热部署过程的实现相当的简陋,其大致思路如下:

    先对webapps目录进行扫描,确定需要部署的App,这里的App是contexts目录中没有的应用,即没有同名的xml文件,部署完这些App之后,用名为 _currentScan 的 Map存储,key是app的路径,value是该目录的最后修改时间,启动定时器,按照设置的间隔时间循环扫描。扫描时用新产生的 _currentScan 和 _prevScan(与_currentScan相同,表示前一次扫描的结果)进行比对,确定差异,添加、修改、删除,分别再触发不同的监听器。
    对于 添加 的应用,直接新增一个部署,对于 删除 的应用,直接删除一个部署,对于 修改 的应用,jetty的做法是先删除,再将应用完全重新部署。
    问题:只有当应用目录的最后修改时间改变了,jetty才认为是应用被修改了,再会重新部署应用,而修改应用中的文件是不会引起应用目录的修改时间改变的,所以,在一般情况下,webapps 中的应用不会被检查到修改。

    而对于contexts目录下的xml文件,和webapps目录一样,也是启动定时器定时扫描,找出更新过的文件,其策略是,如果文件的最后修改时间不同,则表示应该被更新了,则应重新部署应用。
    问题:任何一点小小的改动都能导致xml文件的修改时间变化,比如说在文件中加一个空格,就会导致应用被卸载,然后再被部署。难道不能做得更精致一点?
    对于以上的描述,有代码为证,简单罗列如下:

public class DeploymentManager extends AbstractLifeCycle
{
    ......
    protected void doStart() throws Exception
    {
        if (_useStandardBindings)//如果使用标准的应用生命周期绑定监听器,则添加jetty自带的,否则,用户可自义绑定监听器
        {
            Log.debug("DeploymentManager using standard bindings");
            addLifeCycleBinding(new StandardDeployer());
            addLifeCycleBinding(new StandardStarter());
            addLifeCycleBinding(new StandardStopper());
            addLifeCycleBinding(new StandardUndeployer());
        }

        // Start all of the AppProviders
        for (AppProvider provider : _providers)//默认 _providers 包括两个:ContextProvider 和 WebAppProvider
        {
            startAppProvider(provider);
        }
        super.doStart();
    }

    ......

    //触发应用整个生命周期绑定
    private void requestAppGoal(AppEntry appentry, String nodeName)
    {
        Node destinationNode = _lifecycle.getNodeByName(nodeName);
        // Compute lifecycle steps
        Path path = _lifecycle.getPath(appentry.lifecyleNode,destinationNode);
        if (path.isEmpty())
        {
            // nothing to do. already there.
            return;
        }

        // Execute each Node binding.  Stopping at any thrown exception.
        try
        {
            Iterator<Node> it = path.getNodes().iterator();
            if (it.hasNext()) // Any entries?
            {
                // The first entry in the path is always the start node
                // We don't want to run bindings on that entry (again)
                it.next(); // skip first entry
                while (it.hasNext())
                {
                    Node node = it.next();
                    Log.debug("Executing Node: " + node);
                    _lifecycle.runBindings(node,appentry.app,this);//运行绑定
                    appentry.setLifeCycleNode(node);
                }
            }
        }
        catch (Throwable t)
        {
            Log.warn("Unable to reach node goal: " + nodeName,t);
        }
    }

}

public abstract class ScanningAppProvider extends AbstractLifeCycle implements AppProvider
{
    ......
    protected void doStart() throws Exception
    {
        ......
        File scandir = _monitoredDir.getFile();
        Log.info("Deployment monitor " + scandir + " at interval " + _scanInterval);
        _scanner = new Scanner();
        _scanner.setScanDirs(Collections.singletonList(scandir));//设置要扫描的目录
        _scanner.setScanInterval(_scanInterval);//设置扫描间隔时间
        _scanner.setRecursive(_recursive);
        _scanner.setFilenameFilter(_filenameFilter);//设置文件/目录过滤器
        _scanner.setReportDirs(true);
        _scanner.addListener(_scannerListener);//设置扫描监听器,当文件/目录被新增/删除/修改时触发
        _scanner.start();
    }

    ......

    //应用被修改时触发的动作
    protected void fileChanged(String filename) throws Exception
    {
        if (Log.isDebugEnabled()) Log.debug("changed ",filename);
        App app = _appMap.remove(filename);//先删除
        if (app != null)
        {
            _deploymentManager.removeApp(app);
        }
        app = ScanningAppProvider.this.createApp(filename);//再重新部署
        if (app != null)
        {
            _appMap.put(filename,app);
            _deploymentManager.addApp(app);
        }
    }
}

public class Scanner
{
    ......
    public synchronized void start ()
    {
        if (_running)
            return;

        _running = true;

        if (_reportExisting)
        {
            // if files exist at startup, report them
            scan();
        }
        else
        {
            //just register the list of existing files and only report changes
            scanFiles();
            _prevScan.putAll(_currentScan);
        }
        schedule();//启动定时器
    }

    ......

    public synchronized void scan ()
    {
        scanFiles();
        reportDifferences(_currentScan, _prevScan);//扫描出修改过的应用,包括 新增/删除/修改
        _prevScan.clear();
        _prevScan.putAll(_currentScan);//将当前结果存储起来,以和下一次扫描结果进行比对
    }
}


四、下一步:

jetty 实现 servlet 容器原理分析

jetty Continuation 实现原理分析
分享到:
评论

相关推荐

    C 语言实现 linux pwd 命令内含源码以及说明书可以自己运行复现.zip

    C 语言实现 linux pwd 命令内含源码以及说明书可以自己运行复现.zip

    2024年中国变焦LED手电筒行业研究报告.docx

    2024年中国变焦LED手电筒行业研究报告

    node-v8.11.2-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v4.8.2-x86.msi

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    ffmpeg 结合 SDL 编写播放器内含源码以及说明书可以自己运行复现.zip

    ffmpeg 结合 SDL 编写播放器内含源码以及说明书可以自己运行复现.zip

    2024-2030中国OPzV胶体电池市场现状研究分析与发展前景预测报告.docx

    2024-2030中国OPzV胶体电池市场现状研究分析与发展前景预测报告

    node-v4.9.0-win-x64.zip

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    2024年中国齿轮离心鼓风机行业研究报告.docx

    2024年中国齿轮离心鼓风机行业研究报告

    python教程-03-标签属性的获取和设置.ev4.rar

    python教程-03-标签属性的获取和设置.ev4.rar

    狂雨小说CMS-多功能小说系统

    安装说明 系统要求 PHP要求5.6版本以上,低于5.6版本无法运行 支持php7 addons,application,config,extend,public,runtime,template,uploads 目录必须要有写入权限 777 网站必须配置好伪静态(.htaccess为Apache伪静态配置文件,kyxscms.conf为Nginx伪静态配置文件) 宝塔面板要在 软件 php 设置里安装扩展 fileinfo

    基于java的高校毕业设计选题管理系统论文.docx

    基于java的高校毕业设计选题管理系统论文

    信创微服务平台建设指南(PDF)

    当前,以微服务、DevOps、容器、多云业务管理为代表的云原生技术已经广泛成熟应用,成为加速企业数字化业务高效创新、实现企业数字化转型的最佳技术支撑。而信创支持、国产化支持,是中国企业数字化转型不得不满足的基本要求。更有专家指出,在关乎企业生存的必选项“数字化转型”以及国家信创战略的共同冲击下,企业需要改变现有业务和IT的架构,更快速地应对挑战、响应变化,增强自身的竞争力。 信创微服务平台建设指南应当综合考虑当前的技术发展趋势、企业及用户的需求,以及平台的可持续发展能力。 《信创微服务平台建设指南》可参考文章:https://mp.weixin.qq.com/s/cfJH72JFxDTHCPsfFWMUqA

    node-v8.14.0-linux-ppc64le.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    Python爬虫.pdf

    上文提供了一个基础的Python爬虫示例,旨在从CSDN(一个知名的技术博客平台)上爬取特定文章的内容。这个示例代码展示了使用requests库发送HTTP请求,以及使用BeautifulSoup库解析HTML内容的基本流程。 步骤详解 导入必要的库: requests库用于发送HTTP请求。 BeautifulSoup库用于解析HTML内容。 time库用于控制请求之间的延迟。 设置目标URL和请求头: 目标URL是想要爬取的CSDN文章的URL,这里用占位符'https://blog.csdn.net/some_user/article/details/some_article_id'表示,实际使用时需要替换为真实的URL。 请求头(headers)通常用于模拟浏览器行为,避免被目标网站识别为爬虫。这里设置了User-Agent字段。 发送请求并获取响应内容: 使用requests.get()方法发送GET请求到目标URL,并传入请求头。 使用response.raise_for_status()方法检查请求是否成功。如果响应状态码不是200(成功),则抛出异常。 解析HTML内

    node-v8.2.0-linux-ppc64le.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    毕业设计写作技巧.pdf

    说明: 上文提供了一份关于毕业设计论文写作技巧的总结,旨在帮助学生在完成这一重要学术任务时更加系统、高效地进行。以下是对这份总结的详细说明: 一、目的与重要性 毕业设计论文不仅是学生学术生涯中的一个重要里程碑,也是检验学生综合运用所学知识、独立研究和解决问题能力的重要标准。因此,掌握一定的写作技巧对于顺利完成论文写作至关重要。 二、写作技巧总结 明确研究主题和目标: 学生首先需要确定自己的研究领域和研究方向,确保研究的主题具有实际意义和研究价值。 明确研究目标有助于学生在整个研究过程中保持清晰的方向,确保研究的深入和全面。 充分收集和整理资料: 学生需要通过广泛阅读相关领域的文献,了解研究现状和发展趋势,为论文写作提供充分的理论支撑。 对收集到的资料进行整理和分类,有助于提取有用信息,为论文写作提供有力的论据和支撑。 撰写论文大纲: 论文大纲是论文写作的蓝图,它有助于学生清晰地规划论文的结构和内容。 通过制定合理的大纲,学生可以在写作过程中保持逻辑严密、条理清晰。 论文写作注意事项: 引言部分需要简要介绍研究背景、意义、目的和范围,引起读者的兴趣。 正文部分需要详细阐述研究方

    node-v9.6.1-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    单片机开发资源:基于51单片机的开发程序

    单片机开发资源,基于51单片机的开发程序,供学习参考。

Global site tag (gtag.js) - Google Analytics