目前关注了一下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
...
…
然后把上面的kuaiqian和yibao都打包到单独的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"等跟第三方有关的键值提取到配置,就可以动态的来增加能力。
所以平滑升级已经不是难事。