1

点赞

0

回复

3587

浏览

OSGi的配置管理:ConfigAdmin

动态的OSGI配置 在OSGI语境下,很多元素都脱离不了动态的特征,配置也不例外。我们期望修改配置时可以在不重启OSGI Framework的情况下就能生效,OSGI为此提供了一个ConfigAdmin的机制。首先,看看demo8的代码,demo8里只有一个java类com.ponder.Demo.demo8.configurator,这个类实现了org.osgi.service.cm.ManagedService接口;org.osgi.service.cm.ManagedService接口里只有一个方法:public void updated(Dictionary dctnr);同时,我们在demo8里加了一个blueprint.xml,这个blueprint很简单,只是将configurator这个类实例化,并发布出一个OSGI服务,服务的接口就是org.osgi.service.cm.ManagedService。发布这个服务时,我们指定了一个服务属性:service.pid=com.ponder.Demo.demo8;我们将demo8编译后得到demo8 1.0.jar,将它部署到servicemix上,这时,我们可以通过ls命令看到demo8按我们的预期,发布了一个OSGI服务。我们再手工编辑一个文件:com.ponder.Demo.demo8.cfg demo8package=com.ponder.Demo.demo8...

configadminjavaosgi

3

点赞

1

回复

5030

浏览

初次接触OSGI Blueprint

BLUEPRINT简介 看了《 动态的OSGi服务 http://tianmaying.com/tutorial/osgi service 》后,我们知道,由于OSGI服务的动态性,引用OSGI服务需要大量的代码才可以确保正常。可以想象,如果应用使用了大量的OSGI服务的话,直接使用OSGI API开发OSGI应用的方式显然是不合适的。幸好,OSGI规范里为我们提供了很多方便的方式去使用这些OSGI服务,包括Declarative Service(声明式服务DS)、Blueprint、iPojo等等。 下面,我们来了解一下Blueprint。说到Blueprint,我们首先要提及Spring,相信很多java开发人员都会接触过Spring,作为一个成功的依赖注入(DI)实现框架,Spring被十分广泛地应用在很多java项目中。为了适应OSGI的动态环境,spring发展出spring dynamic modules(SpringDM),Blueprint的规范则是来源于SpringDM的进一步发展。目前,Blueprint规范主要有两个实现:Aries blueprint和Gemini blueprint,它们分别来自Apache和Eclipse两个开源组织。我们后续的课程主要基于Aries Blueprint的实现。Blueprint可以象Spring那样,通过XML的方式构建应用,当然也可以通过Blueprint annotation的方式实现同样的目的。由于XML可以和bundle分离,单独部署到servicemix上,所以比annotation的方式更具灵活性,所以我们推荐使用XML的方式。由于Blueprint和spring的渊源,两者在语法方面十分相似,有spring应用经验开发人员会十分轻松地掌握Blueprint。 BLUEPRINT的入门例子:OSGI服务的注册 我们先来看一个blueprint的简单例子demo6,demo6用blueprint的方式实现和demo2_2一样的功能:发布一个ICalculation的OSGI服务。在demo6中,我们去掉了Activator,同样在Manifest.mf也删除了Bundle Activator项--也就是说,我们不需要写activator的代码啦发布OSGI服务了。我们在demo6里写了一个com.ponder.Demo.demo2.contract.ICalculation接口的实现类com.ponder.Demo.demo6.Impl.Calculation。同时,我们在项目的resources下新建了一个OSGI INF/blueprint的文件夹,里面放了一个xml文件demo6bp.xml,这个文档就起和spring的ApplicationContext.xml类似的作用。以下是这个xml的内容: ...

blueprintosgijava

0

点赞

0

回复

4452

浏览

动态的OSGi服务

OSGI服务的动态性 我们对 OSGi服务 http://tianmaying.com/tutorial/osgi bundle coupling 已经有了初步了解,接上一个 例子 http://tianmaying.com/tutorial/osgi bundle coupling ,我们再次清空/deploy文件夹,并删除/data文件夹; 只将demo3 1.0.jar复制到/deploy文件夹下; 用list命令可以看到demo3 bundle的状态是 installed 然后我们再将demo2 1.0.jar复制到/deploy文件夹下; 用list命令可以看到demo3 bundle的状态变成了 Active ,并且输出了预期的结果。 在以上例子中,我们会发现demo3 bundle是依赖了demo2 bundle,demo3 bundle必须在demo2 bundle成为 Active 的状态时,才能变成 Resolved ,进而转成 Active 的状态。 下面,我们再来做一个试验 demo2 bundle里ICalculation接口和它的实现类Calculation是在一起的。我们建立两个工程(demo2_1和demo2_2),将它们分离开来。 在demo2_1工程里,我们依然有一个com.ponder.Demo.demo2.contract的package,里面也有一个ICalculation的接口类。 在demo2_1的pom.xml里有: ...

javaosgibundleservice

1

点赞

2

回复

3397

浏览

OSGi中Bundle间的耦合:Export/Import Package与服务

创建OSGi Hello World工程 http://tianmaying.com/tutorial/osgi helloworld 里,我们提到OSGI通过不同的classloader来加载不同的bundle,达到隔离bundle的目的,我们也提到通过Import/Export Package的方式来控制bundle之间“有限地”访问对方的类。 这里我们只有一个bundle(demo1 1.0.jar),但我们在这个bundle的manifest.mf里,可以看到设置了Import Package和Export Package。 IMPORT PACKAGE/EXPORT PACKAGE 在OSGI里,bundle暴露自己的类(Export)或引用其他bundle的类(Import)的单位是package(就是每个java代码文件最上头定义的Package),也就是对于bundle来说,只能将整个package里的类暴露或引用进来,而不是对单个类作暴露或引用,所以,我们在设计时,应考虑将需暴露出去的类放在一个或几个package里,而将需隐藏起来的类放在其他的package里。 然后,我们在manifest.mf里加入诸如: Export Package:com.ponder.Demo.demo1...

javabundleosgi

1

点赞

0

回复

4673

浏览

创建OSGi Hello World工程

OSGI BUNDLE工程 在学完《 走近Java模块化系统OSGi http://tianmaying.com/tutorial/osgi kickstart 》后我们已对osgi有初步的印象,今天我们将从一个hello world来具体地接触osgi。 我们将采用maven来构建一个简单的bundle,不熟悉maven的同学请先了解一下再继续。我们还会使用servicemix来做运行时平台,至于IDE,则不限。 首先是maven项目的pom.xml,如下: ...

bundleosgijava

3

点赞

0

回复

5324

浏览

走近Java模块化系统OSGi

OSGI是什么? 刚入软件开发行业的初哥可能会觉得到处都是值得顶礼膜拜的大神,到处都是复杂到自已无法把握的代码,惊叹这些大神怎样能写出如此神奇的程序出来?! 其实真正好的软件的代码,应该是结构清晰,简单易懂的代码(别提linux内核代码,那是另类)。 说到底,软件设计就不外乎复用、内聚、藕合三个主题。 OSGI作为Java的模块化规范,也是为了更好地解决java在这三个主题的问题。 要理解OSGI,首先要知道OSGI不是一个应用层面的框架,而是设计层面的规范,所以不要用理解spring、hibernate、structs那样的框架的方式来理解OSGI,如果一定要找一个类似的东西和OSGI对比的话,我想会是OO(Object Orient面向对象)。所以,不要问“怎么将spring和OSGI集成?”这样的问题,被象你不会问“怎么将spring和OO集成?”一样。 其次,OSGI的目的是模块化,就是为了将一个大的应用分解成较小的模块,这些模块物理上就是一个个的jar包,也就是OSGI bundle。OSGI规范就是指导怎么令这些bundle能更好的有高内聚性、有松藕性,能更好地被复用。至于被神化的“动态性”、“热插拔”的特性,则是OSGI规范带来的一种可能,并不是一定会有的。这些特性是需要配合好的设计才能达到。 最后,OSGI的课程不是去教你学会一种开发语言,也不是去教你学用一套应用框架,而是教你去设计你的应用,是一种形而上的课程,需要个人去领悟。 OSGI FRAMEWORK和BUNDLE的生命周期 OSGI规范定义了一个叫OSGI framework的平台,这个平台是一个运行在JVM上的应用。它负责管理我们上节提到的bundle(也就是一个符合OSGI规范的Jar包)。 对于bundle,我们需要关注它的生命周期。 首先,bundle需要install到osgi framework上,这个install只是让framework用一个classloader来装载bundle里的类和资源。 接着就是resolve,检查bundle需要“引用”的package是否可用,这个后续再详细介绍。 然后,bundle就要start,也就是运行activator里的start方法,方法运行完毕,即进入"ACTIVE"的状态,这时bundle就算正式可用了。 BUNDLE的隔离 “模块化”的模块是一些相对独立的实体,它们是有边界的,就好象我们在OO里看到,类也是有边界的,它一般是以一个类文件作为边界,而OSGI模块的边界则是一个Jar包,也就是一个bundle。简单的说:在OSGI范畴内,模块就是一个bundle,一个bundle就是一个模块。 在传统的java应用开发中,我们很少去关注jar包的隔离性,通常只需要知道我们的应用都用到哪些jar包,在部署时,将这些jar包一起部署,就可以用jar包里的java类了。也就是说,在运行时,一堆的jar包并不需要我们去特意去分辨它们之间的关系,部署好后,该用到谁就自然能用上谁,整个应用就是一体的,jar包的依赖关系并不清晰。 而在OSGI规范下,bundle是被“有计划地”依赖着,你得显式地说明模块之间的依赖关系。OSGI是利用JVM的classloader和它的父委托模型(PDM:Parent Delegation Mode)来实现这点的。 故名思义,classloader就是加载java类的加载器,一个classloader加载的类,就只能被这个classloader及其子classloader加载的其它类访问到。也就是说,如果两个不是父子关系的classloader加载的类是互相不可见的。 而OSGI对每一个bundle都分别用一个classloader来加载里面的类,所以不同bundle之间的类,在默认情况下,是互不可见的。 如果没有额外处理,一个bundle里的类要访问另一个bundle里的类时,通常会出现ClassNotFound的异常,可以说这个异常将是OSGI初学者最常见到的异常。 BUNDLE之间的藕合 一般来说,单个的bundle并不是完整的应用,它需要和其它bundle组合在一起才能真正发挥作用。 在上面,我们提到由于每个bundle的classloader都不同,所以它们的类是互不可见的。 为了能引用别的bundle的类,osgi通过import/export package的机制来控制bundle间有限地藕合。 在bundle的设计时,我们将需要给其它bundle“访问”的类放在若干个package内,然后export这些package,就可以让其它bundle通过import package的方式“访问”到这些package里的类,而没被Export的package里的类则被“保护”起来。 注意: Export/Import package是通过bundle里的META INF/manifest.mf文件里指定的。 更松散的藕合 OSGI SERVICE 除了通过import/export package的机制实现bundle间的藕合,我们还可以通过osgi service的方式实现藕合。osgi service是osgi规范中定义的一种本地服务的机制,“本地”意味着它只是在osgi framework内有效,不可跨osgi framework调用,更不可跨JVM调用。osgi service可以认为是一种“微服务”,可以在bundle之间引用。 osgi framework有一个service registry,bundle可以把一个实现某种接口的bean实例作为osgi service注册(register)到service registry上,其它bundle就可以从service registry上发现并引用它,所以,本质上osgi service就是一个bean。 通常,我们会把接口定义在一个bundle A里,接口的实现则在另一个bundle B里,并将接口实现实例化后注册成osgi service,而第三个bundle C则引用这个osgi service。 因为bundle B和C都需要用到bundle A的接口定义,所以bundle A需export接口定义所在的package,而bundle B和C则需import这个package。这样bundle B和C之间就不需用export/import package来藕合了,实现B和C之间的解藕。 在osgi的应用中,会有大量的osgi service存在,可以说osgi service是osgi规范中最重要的机制,没有之一。 其它机制 OSGI规范还提供了Event、配置管理(ConfigAdmin)、声明式服务(Delarative Service)、Service Tracker、Blueprint等等运行时机制,方便我们构建模块化的应用系统,这些机制,以后再介绍。 ...

osgijavabundle

0

点赞

0

回复

1955

浏览

一种基于OSGi和Docker的SaaS平台热插拔系统设计方案

引言 软件即服务(SaaS)是软件服务业的一个重要发展方向,它使得软件业转向一个运营和服务的模式。大部分的SaaS研究集中于独立软件开发商多租户模型上,本文基于另一种业务模型:单核心软件开发商 多插件软件开发商多租户(Kernel Plugins)模型。核心软件开发商提供核心的软件服务(Kernel)。插件软件开发商可以基于核心软件开发商提供的API,开发额外的插件服务(Plugin)。私有云平台运营者可以将云服务的核心和若干个插件进行部署,并提供给多个租户进行使用。 本文针对Kernel Plugins模型中插件的在线集成和在线演化问题进行深入研究,并提供了一套基于OSGI技术、容器虚拟化技术、前端插件化技术的插件全生命周期管理解决方案。此方案实现了插件化的软件生命周期管理平台onboard。私有云服务提供商可以在不中断服务的情况下完成代码配置管理、迭代、持续集成等软件生命周期管理插件的安装、卸载、升级等操作。在私有云服务提供商改变服务内容时,租户的使用不受影响。证明了此方案是一种可行的SaaS平台插件在线集成、演化方案。 KERNEL PLUGINS业务模型 SAAS生态系统 SaaS发展至今已有近十年的历史,尤其是近几年来,随着互联网接入和使用的大规模普及,软件服务提供商和使用者的供需市场日趋繁荣,SaaS取得了飞速发展,其服务品类和用户数量得以剧增。不断变革的软件产业正经历着由传统软件向“软件即服务”的裂变。 随着市场的不断扩展,产业由早期的SaaS服务商集软件设计开发、服务运营、市场营销、系统集成等角色于一身,到现在逐步开始的分工细化合作,SaaS产业的生态系统正逐渐形成。 在SaaS生态中,主要有以下几个角色: 1. 基础设施供应商 2. 服务组件供应商 3. SaaS软件供应商 4. SaaS运营商 5. SaaS客户 6. … 其中,SaaS软件提供商是整个生态系统的关键角色。它掌握客户对SaaS软件的需求,并将之付诸实践。提供给SaaS运营商,并服务广大的SaaS客户。 SaaS运营商需要向基础设施供应商购买所需的计算及存储资源用来支撑SaaS软件的正常运行。 通常服务组件提供商也是一个SaaS服务提供商。SaaS软件供应商可以通过购买或授权的方式集成服务组件提供商的服务,并将服务组件组合构建新的服务。 从逻辑角度讲,参与SaaS生态系统的不同角色是相互独立存在的,但在实际环境中,很多企业扮演了多重角色。比如很多的SaaS软件供应商同时也在扮演SaaS运营商和服务组件提供商的角色。 模型的应用场景 之前我们介绍了SaaS生态系统中各个角色的作用。假定市场上有一个SaaS服务,它的业务组成为: 1. SaaS软件供应商1名 2. 服务组件供应商若干名 3. SaaS运营商若干名 4. 诸多SaaS客户 SaaS软件供应商提供某服务的核心功能,服务组件供应商基于该服务的核心功能与其他服务整合提供扩展组件。SaaS运营商根据自身资质和客户需求运营核心组件和若干扩展组件。SaaS客户可以根据自身需求的不同选择不同的SaaS运营商。 SaaS运营商的客户群体的需求是不断演变的,在一个SaaS服务的运营过程中,不可避免的要引入之前并未部署的服务组件来满足更多客户的需求。另一方面,SaaS运营商要将不经常使用的组件卸载以减少运营成本。然而,SaaS的运营是一个受SLA(Service Level Agreement)约束的,运营商需要在一定程度上保证服务的正常运行。所以就带来了一个新的需求。 SaaS运营商需要在不中断正常服务的情况下,安装、卸载、升级若干服务组件供应商提供的服务组件。 为了满足SaaS运营商的这个需求,我们提出了一套针对Kernel Plugins模型的插件在线集成和在线演化方案。实践证明,这种方案能够有效的帮助SaaS运营商运行时改变服务的非核心组件。 KERNEL 模型中的Kernel是由SaaS软件提供商提供的一套SaaS核心服务。它通常包含以下几个部分: 1. 核心业务组件 2. 插件注册服务 3. 消息服务 4. Etc. Kernel的核心业务组件会完成SaaS的核心服务,这部分组件的接口不仅仅是面向最终用户的,很大一部分接口是可以令插件提供商进行调用。插件提供商通过将核心业务与自身特色服务进行整合,完成新的插件。插件注册服务是Kernel提供的一个基础服务,插件部署运行后需要向使用插件注册服务来将自身注册到Kernel当中。Kernel维护着运行中的插件列表,通过通用接口完成一系列跟插件有关的业务操作。消息服务是Kernel与Plugin交流的工具,一般来说,它基于发布/订阅模式。Kernel订阅所有Plugin发布的消息,而Plugin可以选择的订阅Kernel核心业务所发布的消息,完成自身的业务逻辑。 PLUGIN的生命周期 Plugin是服务组件提供商,将Kernel的核心业务与自身特色服务整合提供出去的增值服务。Plugin在模型中的主要有如下几个状态: 1. 未安装(NONE): 插件未被SaaS运营商使用。 2. 已下载(DOWNLOADED): 插件被SaaS运营商下载,但未部署。 3. 启动中(STARTING): 插件正在启动过程中。 4. 已启动(ACTIVE): 插件已经启动,可以正常提供服务。 5. 正在停止(STOPPING):插件正在关闭过程中。 在SaaS运营商运营过程中,5种状态可能会经常进行转化,形成了插件的生命周期,它的演化过程如下图所示: 图中虚线表示自动执行的过程,实线表示SaaS运营商进行的操作。运营商的操作有: 1. 下载(download)操作 下载操作需要运营商经过插件提供商的授权,从某个插件托管平台上将插件下载到本地的环境当中。 2. 更新(update)操作 更新操作只能在已下载状态中执行,运营商在插件提供商授权的情况下将本地的插件升级到最新的插件版本。 3. 移除(remove)操作 SaaS运营商主动移除本地插件,并向插件运营商发起解除授权请求,终止插件使用协议。 4. 启动(start)操作 SaaS运营商将本地已下载的插件部署到生产环境当中,对外提供服务。这个操作涉及到三个状态分别是:已下载、启动中和已启动。 5. 停止(strop)操作 SaaS运营商将已部署的插件解除部署,停止对外提供服务。这个操作同样涉及三个状态分别是:已启动、停止中和已下载。 相关技术 为了将Kernel Plugins模型付诸实践。我们引入了一系列技术来支撑方案的实施。主要涉及到部署层面的容器级虚拟化解决方案Docker,Java服务器端的OSGI技术等。 容器级虚拟化解决方案DOCKER Docker是一个开源的应用容器引擎。开发者可以打包他们的应用以及依赖包到一个可移植的容器中,并发布到任何流行的 Linux 机器上。 与传统方式相比,Docker容器的启动可以在秒级实现。其次,Docker对系统资源的利用率很高,一台主机可以同时运行数千个Docker容器。最重要的是对开发运维人员来说仅仅通过一次创建或配置就可以在任意地方正常运行。这一点非常适合Kernel Plugins业务模型的场景。 本文的场景中,存在着多个SaaS的运营者,一个Kernel软件供应商,多个Plugin软件供应商。运营者如果采取传统的方式部署系统的话,需要按照安装文档配置服务器,安装依赖,并维护大量的部署脚本来完成Kernel及Plugin的部署。这是一个相当令人头疼的工作。 引入Docker后,Kernel软件供应商可以将依赖及制品打包到一个镜像中,方便运营者在任意地点部署Kernel,并保证Plugin生命周期管理的基础设施可以正常提供服务。 面向JAVA的动态模型OSGI OSGi技术是指一系列用于定义Java动态化组件系统的标准。这些标准通过为大型分布式系统以及嵌入式系统提供一种模块化架构减少了软件的复杂度。并为开发者提供了一个通用安全可管理的Java框架,能够支持可扩展可下载的应用(即bundles)的部署。 在本文中我们引入OSGI,主要基于以下考虑: 1. OSGI具有动态更新的特性,框架能够帮助BUNDLE动态的安装、启动、停止、更新和卸载。本文服务端插件生命周期的管理就是基于OSGI动态更新的特性来实现的。 2. OSGI使用类加载机制,与JAR包的线性加载不同,它使用bundle的委托式加载,这样类加载就不需搜索。Kernel和Plugin的启动可以更快。 3. OSGI支持组件模型bundle,可以隐藏内部实现,并基于OSGI服务进行交互,有效的降低了Kernel与Plugins集成的复杂性。 实例分析 本节基于一个SaaS实例来展示本文的在线集成和在线演化方案。这个应用是软件生命周期管理平台onboard,它的核心服务是为软件开发企业提供基于任务和回顾的团队协作支持。 然而许多企业是不仅仅满足于使用任务来加速他们的开发进程的。比如有些团队需要代码托管服务来跟踪团队开发人员完成任务的情况。需要文档服务来为团队建立知识资源库等等。 传统的方式是将所有功能都集成到一个软件上,为所有人提供服务。但是这样成本过于高昂,运营商的客户也不一定都有这样的需求。所以引入了本文的方案开发了针对onboard的插件商店,解决了onboard产品插件的发布、安装、升级等问题。 系统架构 上图是onboard插件商店的系统架构图。 系统引入了docker容器引擎,方便运营商对onboard进行部署。我们使用docker分别将Kernel的前端制品和后端制品及相关依赖打包成Docker镜像。 在这里我们采用了前后端分离的方案,这是业界主流的一种做法,将模板渲染工作、URL路由、Session保持等工作交由前端进行。服务器端只负责提供可靠的REST API,当用户操作系统进行业务操作之时,前端会将请求转发给后端由后端完成业务逻辑再将结果展示给用户。这样做的好处是从部署上来说降低了系统的复杂性,加快了系统的启动速度。从开发上来说,前端部分的服务端代码量很少,这样带来的好处是静态资源的刷新速度更快,对于前端开发者来说可以很快的看到改动的结果,提高开发效率。 在插件的管理上,我们在前端和后端容器中分别引入了插件管理器这个组件,通过它我们会去管理前端和后端插件的生命周期。前端插件在此系统中主要为静态文件,包含javascript, css以及html模板。后端插件就是一个Bundle。当用户想要改变某插件的状态时,他需要使用管理界面发起一个变更请求,前端进程接收到请求以后会委托插件管理器改变前端插件的状态,并以REST接口调用的方式通知服务端来完成后端插件状态的更改。任何插件状态的改变都是原子操作。 插件生命周期的管理 前文中, 我们介绍了插件生命周期的各个状态:未安装、已下载、启动中、已启动和正在停止。在4.1中我们又介绍了该方案的基本架构。本节将介绍系统是如何通过该架构完成插件生命周期管理的。 插件制品的形式 在本例中,前端插件的内容为静态文件和thymeleaf模板文件。将正确的静态文件和模板文件分别放置在static目录和templates目录中,将二者打包成一个zip文件,就完成了一个前端制品。 后端制品的形式是OSGI的一个BUNDLE,插件开发者需要使用Maven及felix插件或其他构建工具将插件的后端工程打包成一个Jar包。这个jar包就是该例的后端制品。 插件开发者需要将前端制品和后端制品上传到插件商店当中,并指定版本号,以供SaaS运营者使用。 下载、移除、更新插件 运营者想要将一个插件安装到系统中,首先要经历的过程就是下载插件。前后端插件管理器会向插件商店服务器请求最新版本的下载到本地。下载完成后,会计算下载文件的MD5值并与远端服务器数据进行比对。如若前后端一方下载失败,系统则会重试,直到前后端均下载到了正确的插件。 当插件运营者发起卸载插件的请求时,如果插件处于已下载状态时,前后端的插件管理器会将本地的插件文件及配置删除。 每当插件处于DOWNLOADED状态并向切换到STARTING状态前,系统都会向插件商店服务器请求插件对应版本的MD5值,并与本地进行比对,如若不一致则会执行Update操作。将本地对应版本的插件制品删除,并执行download操作。 另一方面如若SaaS运营商发起了一个插件升级的请求,插件则会同样发起更新请求删除本地版本的插件,下载最新版本的插件,并记录到本地配置当中。 启动、停止插件 插件的启动和停止的过程涉及到插件多个状态的改变。 当SaaS运营商发起插件启动请求时,前后端插件管理器会检查本地插件文件的完整性,如若不完整会执行update操作。检查无误以后,插件管理器会将插件的状态置为启动中,并将后端制品放入Virgo服务器的pickup目录中,前端制品放入前端的静态及模板资源扫描目录。Virgo服务器会去扫描pickup目录,当引入新的jar包,OSGI框架会尝试将Bundle启动,启动完成后会回调后端插件管理器的接口,完成后端插件的启动,后端启动后,后端插件管理器返回成功状态给前端插件管理器,前端插件管理器会将通知前端模板引擎和静态资源解析器将页面资源引入到线上系统中。并将插件状态置为ACTIVE。 当插件状态在Starting到ACTIVE的任一环节出错的话,插件管理器会尝试回滚操作,包括删除静态和模板文件、删除Bundle文件、停止Bundle、解除前端模板引擎和静态资源解析器对该插件静态资源的渲染。 当SaaS运营商发起插件中止请求时,会首先删除后端插件的Bundle文件,Virgo服务器扫描到删除事件后,会尝试停止Bundle,停止后会回调后端插件管理器,插件管理器会去通知前端插件管理器删除静态及模板文件,解除前端模板引擎及静态资源解析器对插件目录的扫描,中止提供服务。同样,插件的中止操作也是原子操作。 KERNEL与PLUGIN的交互 除了对插件生命周期的管理外,插件还需要通过与Kernel的交互完成它的业务逻辑。在本例中采用了如下几个方面的交互。 服务端插件注册 插件注册是插件与内核交互的最基本手段,通过将插件的一些实现Kernel接口的实体注册到Kernel当中,就可以通过接口将插件的信息织入到Kernel当中,完成扩展。本例中使用了OSGI的监听技术来支撑这一实现,在Kernel中,我们会监听使用某接口定义的OSGI服务的建立事件,并维护一个接口列表。 ...

saasosgidocker

新建主题 记录代码

学员动态

  • 水**漪添加了笔记:private:表示...
  • S**S评论了a**e在课程中的作业:List<Strin...
  • t**t添加了笔记:泛型类支持多个类型参...
  • 一**狗向课程作业中提交了代码
  • l**9向课程作业中提交了代码
  • 斑**斓向课程作业中提交了代码
  • 一**狗向课程作业中提交了代码
  • F**n向课程作业中提交了代码
  • S**S评论了d**g在课程中的作业:要在你本地的Ecli...
  • F**e向课程作业中提交了代码
  • T**M向课程作业中提交了代码
  • 咲**i在课程中提出了问题:老师我虽然完成了这个...
  • b**i添加了笔记:数学运算中存在自动类...
  • 天**君评论了d**g在课程中的作业:要设置输...
  • c**e在课程作业中回复了老师:understand...
  • j**e在课程作业中回复了老师:怎么调用 不同数据类...
  • 天**君回复了d**g在课程中的问题:代码提交上...
  • d**g在课程作业中回复了老师:好的,那除了这个还有...
  • 天**君评论了d**g在课程中的作业:如何运行代码还记得吗...
  • 一**狗在课程中提出了问题:为什么不直接构造第三...
  • R**c向课程作业中提交了代码
  • 咲**i在课程中提出了问题:还有就是 我用的ec...
  • t**t添加了笔记:,且每个代码块只能执...
  • 天**君评论了d**g在课程中的作业:你把代码贴到本地。注...
  • d**7在课程作业中回复了老师:老师,我这个题 做不...
  • t**t添加了笔记:,且每个代码块只能执...
  • h**g在课程中提出了问题:可以了,我把最新版本...
  • t**t添加了笔记:时Point成为了一...
  • b**i添加了笔记:3.所有的标识符都应...
  • t**t添加了笔记:泛型类支持多个类型参...
  • 天**君回复了一**狗在课程中的问题:在其它的调用场景下可...
  • a**e在课程作业中回复了老师:[博客创建时间] ...
  • R**d向课程作业中提交了代码
  • b**i添加了笔记:a++;a += 1...
  • j**e向课程作业中提交了代码
  • c**e在课程作业中回复了老师:what is th...
  • c**e向课程作业中提交了代码
  • F**e向课程作业中提交了代码
  • L**R向课程作业中提交了代码
  • 天**君回复了R**d在课程中的问题:欢迎来到天码营学习,...
  • R**c向课程作业中提交了代码
  • c**e向课程作业中提交了代码
  • 8**u添加了笔记:包装 Integer...
  • t**t添加了笔记:泛型类支持多个类型参...
  • 天**君回复了a**e在课程中的问题:欢迎来到天码营学习,...
  • c**e向课程作业中提交了代码
  • c**e在课程作业中回复了老师:oh thx btw...
  • R**c向课程作业中提交了代码
  • d**g在课程作业中回复了老师:老师,我找到cons...
  • t**t添加了笔记:有static修饰的...
  • F**e向课程作业中提交了代码
  • t**t添加了笔记:编译器会将初始化构造...
  • d**g在课程中提出了问题:public voi...
  • d**7向课程作业中提交了代码
  • 天**君评论了j**e在课程中的作业:看看编译错误提示,你...
  • t**t添加了笔记:因此,在方法执行时,...
  • h**g在课程中提出了问题:这是什么情况啊,把系...
  • t**t添加了笔记:意实际传入的类型参数...
  • 斑**斓向课程作业中提交了代码
  • L**R添加了笔记:'=='和'!='作...
  • S**S评论了d**0在课程中的作业:因为 前 面几项 是...
  • d**g在课程作业中回复了老师:先前不是您说没问题的...
  • d**g在课程作业中回复了老师:麻烦老师帮我看一下这...
  • k**5添加了笔记:除了逐个类的引入之外...
  • b**0添加了笔记:注意,将一个整数和字...
  • d**7向课程作业中提交了代码
  • F**e向课程作业中提交了代码
  • F**e向课程作业中提交了代码
  • 天**君回复了咲**i在课程中的问题:后面会讲解代码的意思...
  • c**e在课程作业中回复了老师:And, why i...
  • 咲**i在课程中提出了问题:对呀 如果是在cla...
  • T**M向课程作业中提交了代码
  • y**9向课程作业中提交了代码
  • 斑**斓添加了笔记:方法名相同,但是参数...
  • d**g在课程作业中回复了老师:可是运行之后显示这一...
  • d**g在课程中提出了问题:老师,请问代码哪里出...
  • b**0添加了笔记:Integer in...
  • b**i添加了笔记:1.public s...
  • b**i添加了笔记:2.注意System...
  • a**e在课程作业中回复了老师:[博客创建时间] ...
  • b**g添加了笔记:Java要求在使用一...
  • L**R添加了笔记:与大部分编程语言相同...
  • d**g在课程中提出了问题:代码已经提交,麻烦老...
  • A**e在课程中提出了问题
  • t**t添加了笔记:而对于静态变量在内存...
  • L**R添加了笔记:Scanner sc...
  • b**i添加了笔记:4.Java中的注释...
  • A**e在课程中提出了问题:为啥我分别创建两个新...
  • F**e向课程作业中提交了代码
  • t**t添加了笔记:因此,在方法执行时,...
  • 一**狗添加了笔记:increase(i...
  • L**R向课程作业中提交了代码
  • k**5添加了笔记:import jav...
  • 天**君评论了t**t在课程中的作业:”天码营的一篇博客“...
  • b**i添加了笔记:以加法运算为例,如果...
  • 一**狗向课程作业中提交了代码
  • l**r向课程作业中提交了代码
  • b**0添加了笔记:String str...
  • l**9向课程作业中提交了代码
  • 斑**斓添加了笔记:String for...
反馈意见