osgi学习进阶(一)

目前关注了一下osgi,并在网上找了相关代码,最后分析了一下如何用到我们的统一支付,来解决平滑升级的问题,大家可以看一下。

 

什么是OSGI?

OSGi(Open Service Gateway Initiative)

OSGi事一个服务平台提供在多种网络设备上无需重启的动态改变构造的功能

OSGI就像一个容器,往里面按照多个组件(bundle),各个bundle可以热插拔,而且可以访问到彼此

 

OSGi是一个Java框架,该框架能装载以bundle为单位的资源。Bundle能提供服务或响应处理请求,而他们之间的依赖都是被管理起来的,正如一个bundle能从容器中获得它所需要的管理。每个bundle都可以有它自己的内部类路径,所以它可以作为独立的服务单元。所有的这些符合OSGi规范的bundle理论上都可以安装在任何符合OSGi规范的容器中

 

OSGi 试图把Java的模块化部署标准化起来,而不是强行往Java EE概念上靠拢,这样也能避免Java EE关于依赖和版本检测以及生命周期方面的弱点

 

bundle提供了生命周期和服务暴露

 

 

 

如何构建一个bundle?:

 

准备一个应用,比如:

 

package baselib;

 

import java.util.logging.Logger;

 

public   class BaseService {

 Logger log = Logger.getLogger( this .getClass().getName());

   public   void sayHello() {

    log.info( " Hello, world! " );

 }

}

 

将上面这个类打成一个jar baselib.jar

 

然后做一个生命周期管理器,并在启动时调用上面这个应用

package tutorial;

 

import baselib.BaseService;

 

import org.osgi.framework.BundleActivator;

import org.osgi.framework.BundleContext;

 

import java.util.logging.Logger;

 

public   class TutorialActivator implements BundleActivator {

 Logger log = Logger.getLogger( this .getClass().getName());

   public   void start(BundleContext bc) {

    log.info( " started " );

     new BaseService().sayHello();

 }

 

   public   void stop(BundleContext bc) {

    log.info( " stopped. " );

 }

}

 

将上面这个管理器还有baselib.jar打成一个jar tutorialbundle.jar

并在MANIFEST.MF输入以下启动信息

 

Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-SymbolicName: com.theserverside.tutorial.osgi.TutorialBundle

Bundle-Version: 1

Bundle-Activator: tutorial.TutorialActivator

Import-Package: org.osgi.framework ; version="1.3.0"

Bundle-ClassPath: . , baselib.jar

 

上面的步骤就完成了一个bundle的开发。

 

如何运行bundle

 

我们要先下载一个OSGI容器,比如Equinox,这个也是Eclipse用的OSGI容器

Equinox 是一个OSGi容器,你可以从http://download.eclipse.org/eclipse/equinox/ 下载。

 

 

启动osgi

java -jar org.eclipse.osgi_3.3.2.R33x_v20080105.jar –console

 

 

osgi控制台输入以下指令,注意必须用资源提示符:

osgi> install file:///tutorialbundle.jar

Bundle id is 1

 

osgi> start 1

2010-12-22 12:29:06 tutorial.TutorialActivator start

信息: started

2010-12-22 12:29:06 baselib.BaseService sayHello

信息: Hello, world!

 

osgi> stop 1

2010-12-22 12:29:15 tutorial.TutorialActivator stop

信息: stopped.

 

可以通过 Osgi > ss 来看当前的组件运行情况

osgi> ss

 

Framework is launched.

 

id      State       Bundle

0       ACTIVE      org.eclipse.osgi_3.6.1.R36x_v20100806

1       ACTIVE      com.theserverside.tutorial.osgi.TutorialBundle_1.0.0

7       ACTIVE      repository_1.0.0

8       ACTIVE      samplerepouser_1.0.0

 

 

MANIFEST.MF解释

Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: Repository Plug-in

Bundle-SymbolicName: repository

Bundle-Version: 1.0.0

Bundle-Activator: repository.Activator 生命周期管理器

Bundle-Vendor: theserverside.com

Import-Package: org.osgi.framework ; version="1.3.0", org.osgi.util.tracker ; version="1.3.1"

Export-Package: repository ; uses:="org.osgi.framework"   暴露这个包下面的所有类供别人使用

Require - Bundle: repository 要求导入这个包下面的类

Bundle-ClassPath: . , xom-1.2.6.jar ,xml-apis.jar 这个bundle依赖的包

 

 

 

如何在同一个OSGI下访问别的bundle,并访问它的类包?

 

提供服务的bundle

在生命周期管理器里注册服务,通常实现都配置在spring里,然后实现是打包在jar里,以下是直接硬代码

 

context.registerService(RepositoryService.class.getName(),

new XMLRepositoryService(), new Hashtable<Object, Object>());

 

寻求服务的bundle

在生周期管理器里查询服务

ServiceReference ref = context

.getServiceReference(RepositoryService.class.getName());

RepositoryService lookup = (RepositoryService) context.getService(ref);

 

当中用到共享的类包可以通过Export-Package来分享,通过Require - Bundle来导入,比如上面用到RepositoryService这个接口,但是这个接口在repository_1.0.0这个bundle里,那么就需要repository_1.0.0暴露这个类,然后当前组件通过Require - Bundle来接纳这个类。

 

 

OSGI对我们有什么用?

 

我们现在每次修改第三方处理行为都要重启服务器,如果我们把第三方服务通过接口和实现分离,在我们的统一支付里使用接口来访问第三方类包,把每个第三方的具体业务实现封装到单独的jar里,那么就可以做到不需要重启统一支付,通过OSGI就可以访问到第三方的具体业务实现上。

项目结构可能是这样的

Com.skymobi.application.paymentplat

Com.skymobi,application.thirdparty.kuaiqian

Com.skymobi,application.thirdparty.yibao

...

 

然后把上面的kuaiqianyibao都打包到单独的osgi jar,比如kuaiqian.jar,yibao.jar等等

 

以块钱为例,在运行上面的bundle的时候使用

context.registerService("kuaiqian",

new KuaiQianThirdPartyService(), new Hashtable<Object, Object>());

来注入到OSGI容器。

 

 

paymentplat通过

ServiceReference ref = context.getServiceReference("kuaiqian");

ThirdPartyService lookup = (ThirdPartyService) context.getService(ref);

就获取到一个处理请求块钱的的实例

 

 

如果块钱需要升级,那么先stop上面的块钱OSGI,如果这个时候paymentplat需要访问块钱,那么会获取到一个null的实例,可以做一下判断,就可以知道块钱目前处在不可用状态。

 

如果我们要加一个新的第三方,也很容易,只要我们把上面的"kuaiqian"等跟第三方有关的键值提取到配置,就可以动态的来增加能力。

 

所以平滑升级已经不是难事。

原文地址:https://www.cnblogs.com/sunwei2012/p/1913891.html