豆角茄子子

导航

Apache Karaf调研

一、名词解释

(一)OSGi

OSGi(Open Service Gateway Initiative),开放服务网关协议,是Java动态化模块化系统的一系列规范。

基于Spring DM发展而来。

使用OSGi的基本目标:高度模块化,高度解藕,SOA,好维护。

OSGi最重要的特性:

在Java中ClassLoader是非常重要的概念,而大家也知道,JVM本身在ClassLoader上并没有提供非常强大的功能,比如模块开发非常重要的模块隔离ClassLoader的机制、版本加载机制等。OSGI基于JVM ClassLoader形成模块隔离ClassLoader的机制,同时也增强了ClassLoader按版本加载、属性过滤等多种功能。

Java和J2EE的类加载模型都是层次化的,只能委托给上一层类加载器;而OSGi类加载模型则是网络图状的,可以在bundle间互相委托。这样更合理,因为bundle间的依赖关系并不是层次化的。

(二)Karaf

Karaf是2001年Apache旗下的一个开源项目,Karaf同时也是一个基于OSGi的运行环境,Karaf提供了一个轻量级的OSGi容器,可以用于部署各种组件,应用程序。

Karaf提供了很多特性用于帮助开发者和用户更加灵活的部署应用,例如:热部署,动态配置,几种日志处理系统,本地系统集成,可编程扩展控制台,ssh远程访问,内置安装认证机制等等。

(三)Bundle

即osgi中的模块。最终在karaf容器中表现为一个jar包。1个bundle对应1个OSGi ClassLoader。

Bundle之间类的共享:

通过 export package的方式实现的,在bundle的manifest中通过指定export package的方式将特定的package与其他的bundle共享。而引用其他bundle所暴露的package有两种方式,第一是通过 import package的方式,第二种是通过required bundle的方式。

(四)模块

一个模块应该具有以下3个特性:

  • 自包含:一个模块应该是一个业务逻辑的整体,它应该可以作为一个独立的整体被移动、安装和卸载。模块不是一个原子体,它可以包含多个更小的部分,但这些部分不能独立存在。
  • 高内聚:一个模块不应该做很多不相关的事情,它应该专注于1个业务逻辑的目标并尽全力实现这个目标。
  • 低耦合:一个模块不应该关注其他模块的内部实现,松散的联系允许我们去更改某个特定的模块,而不会影响到其他的模块。

而Java语言的Jar文件并不能完美的实现一个模块这3个特性,它主要会遇到以下的3个问题:

  • 1、针对一个Jar文件,没有对应的Java运行时的概念。Jar文件只有在开发和部署的时候有意义,而在JVM中,所有的Jar文件中的内容被简单地联系在一起作为一个单独的全局的列表,这就是所谓的“Classpath”。这种类加载模式,使Jar文件在运行时是不可见的。
  • 2、Jar文件没有标准的元数据信息去指明该Jar文件所需要的外部依赖文件列表,这样我们就不能清楚的知道,该Jar文件需要和其他的那些Jar文件一起工作。另外,现在的Jar文件没有版本信息,这样,同一Jar文件的多个版本就不能同时被加载。
  • 3、Java没有机制在不同的Jar文件中隐藏信息。

这3个问题,使Jar文件在模块的“自包含”和“低耦合”这两个特性上做的不好,从而使Java在模块的“拆分人力”和“易于维护”这两个优点上没有好的表现,而更严重的是第2个问题,这使Java应用软件存在难以处理的版本冲突问题。

(五)Feature

即一组bundle,其具备特定的功能。

(六)Blueprint

是OSGi的DI框架或OSGi依赖注入的标准,非常类似于spring上下文。以xml的方式构建应用。用来处理POJO对象的装配,可以达到跨bundle访问对象。使用blueprint上下文将xxService作为一个OSGi服务发布。

其有2个具体实现:Apache的Aries、Eclipse的Gemini。

包含的子标签:bean、service、reference、reference-list等等。

(七)Configuration admin

OSGi容器包含一个非常好的配置规范:来自企业级规范的Config Admin服务。可以在bundle中自动部署配置文件。

基本上在Config Admin服务中的配置是一个字典,这个字典包含了属性和他们的值。字典由持久性标识PID标识。PID就是一个简单的字符串,它唯一标识了配置。

文件结尾是.cfg,则它认为这是一个config admin资源,创建或更新由文件名确定的pid的Config Admin服务配置。

(八)CXF

CXF 框架是一种基于 Servlet 技术的 SOA 应用开发框架,要正常运行基于 CXF 应用框架开发的企业应用,除了 CXF 框架本身之外,还需要 JDK 和 Servlet 容器的支持。

CXF 继承了 Celtix 和 XFire 两大开源项目的精华,提供了对 JAX-WS 全面的支持,并且提供了多种 Binding 、DataBinding、Transport 以及各种 Format 的支持,并且可以根据实际项目的需要,采用代码优先(Code First)或者 WSDL 优先(WSDL First)来轻松地实现 Web Services 的发布和使用。

二、Karaf常用命令

(一)查看所有bundle启动状态

list或者bundle:list

(二)查看所有配置文件列表

config:list

注:配置文件所在路径为${KARAF_HOME}/etc/xx.cfg

(三)改变配置

config:edit ConfigApp
config:property-set title “A better title”
config:property-list
config:update

注:ConfigApp为示例bundle的名称

(四)启动

karaf或者karaf.bat

(五)停止

shutdown或halt或logout或快捷键Ctrl+D
shutdown 10代表10min后关闭karaf

(六)获取帮助

opt --help

注:opt代表具体的命令,如shutdown --help

(七)查看日志

log:display或log:tail -n 20

注:日志所在目录为${KARAF_HOME}/data/log

(八)添加、安装、部署feature应用

feature:repo-add camel
feature:install deployer camel-blueprint aries-blueprint
feature:install webconsole

(九)停止、卸载应用

bundle:stop example.xml
bundle:uninstall example.xml

注:example.xml为示例bundle名

(十)查看所有http服务列表

http:list

注:http端口配置文件位置为${KARAF_HOME}/etc/org.ops4j.pax.web.cfg

三、目录结构

四、Karaf特性

Karaf是基于Equinox或者Felix的OSGi容器。相对于其它优良的容器来说,主要的不同点是karaf带来了优秀的features管理。

Karaf的杰出特性:

  1. 类似于Bash的完备feature扩展控制台
  2. SSH控制台
  3. 从maven仓库部署bundle和feature
  4. 易于从命令行创建新的实例

所有这些特性使得开发基于服务器的OSGi应用几乎与常规的Java应用一样容易。

五、创建并安装一个小OSGi应用

示例工程tasklist源码位置:

https://github.com/cschneider/Karaf-Tutorial/zipball/master

Tasklist示例包含4个子工程:

Moudle

描述

tasklist-model

服务接口和任务类

tasklist-persistence

简单的持久实现,提供了TaskService

tasklist-ui

Servlet,使用TaskService显示任务列表

tasklist-features

应用的Feature描述,这样在Karaf中安装会很容易

(一)父pom和一般项目设置

pom.xml是打包bundle包,maven-bundle-plugin使用OSGi Manifest创建jar。默认情况下,插件会导入所有在java文件中导入或在blueprint上下文中引用的包。

它还导出所有不包含字符串impl或internal的包。在我们的例子中,我们希望导入模型包,而不是persistence.impl包。由于使用命名约定,我们不需要额外的配置。

(二)Tasklist-model

这个项目包含模型,在我们的例子中它是Task类和TaskService接口。tasklist-persistence和tasklist-ui都使用该模型。 TaskService的任何用户都只需要该模型。所以它永远不会直接绑定到我们当前的实现。

(三)Tasklist-persistence

非常简单的持久化实现TaskServiceImpl在一个简单的HashMap中管理任务。该类使用@Singleton注释将类公开为blueprint的bean。

注释@Service将bean公开为OSGi服务,properties属性允许添加service属性。在我们的例子中,我们设置的属性service.exported.interfaces可以由CXF-DOSGi使用,我们将在后面的教程中介绍它。对于本教程,也可以删除属性。

@Service(classes=TaskService.class,
properties= {
		@ServiceProperty(name = "service.exported.interfaces", values = "*")
})
@Singleton
public class TaskServiceImpl implements TaskService {
	...
}

blueprint-maven-plugin将处理上面的类并自动创建合适的blueprint的xml,这样就省去了我们手工编写blueprint的xml。
可以在target/generated-resources中找到自动创建的blueprint的xml。

自动生成的xml:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
	<bean id="taskService" class="net.lr.tasklist.persistence.impl.TaskServiceImpl" />
	<service ref="taskService" interface="net.lr.tasklist.model.TaskService" />
</blueprint>

(四)Tasklist-ui

ui项目包含一个小的servlet TaskServlet来显示任务列表和各个任务。要处理任务,servlet需要TaskService。我们使用注释@Inject注入TaskService,注释@Inject能够按类型注入任何bean,注释@Service创建对给定类型的OSGi服务的blueprint引用。
整个类作为接口java.http.Servlet的OSGi服务公开,具有特殊属性osgi.http.whiteboard.servlet.pattern = /tasklist。这会触发pax web的whiteboard扩展程序,它会获取服务并将其作为servlet导出到相对url /tasklist。

相关代码的片段:

@Service(classes = Servlet.class,
	properties = {
		@ServiceProperty(name = "osgi.http.whiteboard.servlet.pattern", values = "/tasklist")
	}
) 
@Singleton
public class TaskListServlet extends HttpServlet {
    @Inject @OsgiService
    TaskService taskService;
}

自动生成的xml:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
	<reference id="taskService" availability="mandatory" interface="net.lr.tasklist.model.TaskService" />
	<bean id="taskServlet" class="net.lr.tasklist.ui.TaskListServlet">
		<property name="taskService" ref="taskService"></property>
	</bean>
	<service ref="taskServlet" interface="javax.servlet.http.HttpServlet">
		<service-properties>
			<entry key="alias" value="/tasklist" />
		</service-properties>
	</service>
</blueprint>

(五)Tasklist-features

最后一个项目只为maven资源库安装了一个功能描述符,因此我们可以在Karaf中轻松安装它。描述符定义了一个名为tasklist的功能,以及要从maven存储库安装的包。

features.xml:

<feature name="example-tasklist" version="${pom.version}">
   <feature>example-tasklist-persistence</feature>
   <feature>example-tasklist-ui</feature>
</feature>

<feature name="example-tasklist-persistence" version="${pom.version}">
	<bundle>mvn:net.lr.tasklist/tasklist-model/${pom.version}</bundle>
	<bundle>mvn:net.lr.tasklist/tasklist-persistence/${pom.version}</bundle>
</feature>

<feature name="example-tasklist-ui" version="${pom.version}">
    <feature>http</feature>
    <feature>http-whiteboard</feature>
	<bundle>mvn:net.lr.tasklist/tasklist-model/${pom.version}</bundle>
    <bundle>mvn:net.lr.tasklist/tasklist-ui/${pom.version}</bundle>
</feature>

一个功能feature可以包含其他应安装的功能和要安装的bundle包。bundle包通常使用mvn url。这意味着它们是从配置的maven存储库或〜/.m2/ repository中的本地maven存储库加载的。

(六)安装应用

Karaf命令:

feature:repo-add mvn:net.lr.tasklist/tasklist-features/1.0.0-SNAPSHOT/xml
feature:install example-tasklist-persistence example-tasklist-ui

将功能描述符添加到Karaf,以便将其添加到可用功能中,然后安装并启动任务列表功能。执行此命令后,应运行tasklist应用程序。

(七)补充总结

1.pom.xml配置

父和feature工程pom.xml指定:

<packaging> pom <packaging>

tasklist-model、tasklist-persistence、tasklist-ui工程指定:

<packaging> bundle <packaging>

2.Maven相关插件配置

maven-bundle-plugin使用OSGi Manifest创建jar。

blueprint-maven-plugin将为带blueprint注解的类自动创建合适的blueprint的xml,这样就省去了我们手工编写blueprint的xml。

六、在bundle中自动部署配置文件

示例工程configadmin源码位置:

https://github.com/cschneider/Karaf-Tutorial/tree/master/configadmin

我们首先快速概览一下Configuration Admin服务规范。对于我们来说,主要有两个接口可以使用:

  • ConfigurationAdmin:允许获取和改变配置。这个服务由Config Admin服务实现提供。
  • ManagedService:允许对配置改变产生影响。必须实现这个接口,并将它注册给要被通知的服务。

处理配置文件改变的2种方式:

  • 纯OSGi API(实现ManagedService)
  • blueprint方式:

只要将blueprint上下文放在OSGI-INF/blueprint目录中并且blueprint extender加载了,那么blueprint上下文就被会简单地激活。

定义了一个cm:property-placeholder元素。这个处理文件的属性占位符的功能很相似,但是这里是处理Config Admin服务。我们需要提供一个配置的PID和更新策略。更新策略我们选择“reload”。这意味着在配置改变之后,blueprint上下文会被重新加载或反射改变。我们也设置了默认的属性,当配置的PID找不到或者属性不存在的时候,就会使用这些默认值。

<cm:property-placeholder persistent-id="ConfigApp" update-strategy="reload" >
	<cm:default-properties>
		<cm:property name="title" value="Default Title"/>
	</cm:default-properties>
</cm:property-placeholder>

<bean id="myApp" class="net.lr.tutorial.configadmin.MyApp" init-method="refresh">
	<property name="title" value="${title}"></property>
</bean>

在我们成功地使用了Config Admin服务之后,剩下要做的唯一一件事就是部署带默认配置的bundle。这可以使用Karaf feature文件实现。我们定义一个feature,带有它需要的bundle,简单地添加一个configfile元素。这使得Karaf部署给定的文件到Karaf安装位置的etc目录。如果这个文件已经存在,那么它不会被覆盖。

<feature name="tutorial-configadmin" version="${pom.version}">
	<bundle>mvn:net.lr.tutorial.configadmin/configapp/${pom.version}</bundle>
	<bundle>mvn:net.lr.tutorial.configadmin/configapp-blueprint/${pom.version}</bundle>
	<configfile finalname="/etc/ConfigApp.cfg">mvn:net.lr.tutorial.configadmin/configadmin-features/${pom.version}/cfg</configfile>
</feature>

七、其他

本文档略去以下Karaf相关部分:

  • 使用WebConsole改变配置
  • CXF服务
  • Camel集成
  • 数据库DataSource访问
  • JPA持久化&JTA事务
  • 分布式OSGi
  • 基于注解的blueprint&JPA
  • 声明式服务DS

八、Kettle中的OSGi

(一)相关项目

pentaho-karaf-assembly项目包含Karaf组件以及两个子模块,pentaho-blueprint-activators和pentaho-karaf-features。 

pentaho-karaf-features  包含用于Open(标准)和EE(企业)的Pentaho Karaf功能文件。每个特征文件都使用它自己的分类器pentaho-karaf-features- [分类器]发布。 

pentaho-blueprint-activators包含 带有激活bean定义的OSGI Blueprint文件。这些由Pentaho功能引用,旨在引导功能环境。每个文件都使用它自己的分类器发布,这样工件就是pentaho-blueprint-activators- [classifier]。根据需要添加激活器以支持您的功能。但是,如果该功能包含可容纳激活器文件的Pentaho Bundle,请执行此操作而不是在此处添加。

主程序集首先构建功能和激活器模块。

(二)PDI-OSGi Bridge

顾名思义,“桥梁”充当PDI的PluginRegistry和OSGI之间的中间人。该桥能够将OSGI包发布的任何PDI插件类定位到Service Registry。由于OSGI是一个动态系统,可以在程序执行期间的任何时刻安装和卸载软件包,因此PluginRegistry中添加了一项新功能来监听这些插件事件。例如,Spoon UI会在添加或删除步骤时更新步骤。

希望利用OSGI技术的插件开发人员不需要了解Bridge的内部细节,只需要了解如何开发OSGI包以及如何在PDI环境中部署它们。

(三)为何选择OSGi

OSGI是行业标准的模块化软件框架。它的设计取代了插件架构。核心代码和扩展使用相同的模块化设计Bundles构建,最接近插件的概念。在OSGI中,一切都在同一个基础上。Versionsed类可以在bundle之间自由共享,允许平台的受控扩展。OSGI环境具有内置的弹性,可在运行时更改捆绑软件的安装和卸载。

事实上,迁移到OSGI并没有将一个插件系统交换到另一个插件系统。相反,它正在转向一个根本不需要插件系统的架构。

(四)Kettle启动过程以及加载插件过程

下图为Kettle启动脚本:

通过分析studio.bat脚本,不难定位到Kettle的引导包launcher.jar。

launcher.jar来源于component/pentaho-common/pentaho-application-launcher工程,所以要想通过编译完整的Kettle工程来启动的话,需要先编译component,后编译main。

若想调试,可添加上面的调试语句。

  • Launcher.java:

读取launcher.properties文件,根据其中配置,加载运行Spoon类的main方法。文件内容如下:

  • Spoon.java:

1.创建了一些日志文件或其他目录;

2.启线程池,注册插件;

3.KettleEnVironment.init()

KettleEnVironment类包含Kettle所有配置可供读取,也可注册各种插件,如下:

方法调用栈:

PluginRegister.init()

->PluginRegister.registerType()遍历extentions

  ->OSGiPluginRegisterExtention.searchForType()

    ->OSGiPluginTracker.registerPluginClass()

(五)相关类

  • BundleActivator:与OSGI交互或需自定义start/stop bundle时的处理。(BridgeActivator impl BundleActivator)
  • BundleContext:与OSGI通信。
  • Bundle:管理已安装的bundle生命周期。

九、参考资料

1.官方文档http://karaf.apache.org/manual/latest/

2.原开发者Confluence:http://www.liquid-reality.de/display/liquid/2011/02/15/Karaf+Tutorial+Part+1+-+Installation+and+First+application#space-menu-link-content

3.OSGi基本原理:http://www.docin.com/p-2060423828.html

4.Bundle生命周期:https://blog.csdn.net/vking_wang/article/details/12373463

5.OSGi类加载:https://blog.csdn.net/vking_wang/article/details/12875619

6.Kettle插件加载:

https://blog.csdn.net/czmacd/article/details/52957188

https://blog.csdn.net/u013468915/article/details/82629715

https://blog.csdn.net/d6619309/article/details/50654355

https://blog.csdn.net/czmacd/article/details/52956445

https://blog.csdn.net/bluebelfast/article/details/43192995

 

posted on 2018-10-09 23:40  豆角茄子子  阅读(1503)  评论(0编辑  收藏  举报