OSGi入门必读系列《OSGi服务:非常适合SOA的架构》
2017-10-12 22:05
405 查看
OSGi是一个非常适合实现面向服务的应用(SOA)。
可以让Bundles导出服务,而其他Bundles可以在不了解源Bundles任何信息的情况下消费这些导出的服务。
(1)导出服务:
更新HelloService Bundle,以便能把HelloServiceImpl类的对象导出为服务。(接前面的内容)
A、确认在HelloService Bundle中的MANIFEST.MF文件中导入了org.osgi.framework包
B、在HelloService Bundle中的src文件下创建一个在com.javaworld.sample.helloservice.impl包下的HelloServiceImpl.java文件,代码如下:
public class HelloServiceActivator implements BundleActivator {
ServiceRegistrationhelloServiceRegistration;
public void start(BundleContext context)throws Exception {
HelloService helloService = newHelloServiceImpl();
helloServiceRegistration=context.registerService(HelloService.class.getName(), helloService, null);
}
public void stop(BundleContext context)throws Exception {
helloServiceRegistration.unregister();
}
}
在源Bundle中,使用BundleContext.registerService()方法来导出服务,该方法有三个参数:
i)第一个参数是要注册的服务的接口名称。
如果想把服务注册到多个接口下,需要新建一个String数组存放这些接口名,然后把这个数组作为第一个参数传给registerService()方法。上面代码中,想把服务导出到HelloService接口名下。
ii)第二个参数是要注册的服务的实际JAVA对象。上面代码中,导出HelloServiceImpl类的对象,并将其作为服务。
iii)第三个参数为服务的属性,是一个Dictionary对象。如果多个Bundle导出服务的接口名相同,目标Bundle就可以使用这些属性对源进行过滤,找到感兴趣的服务。
C、最后修改HelloService Bundle中的MANIFEST.MF文件中的Bundle-Activator属性头的值,改为第二步新建文件,即“com.javaworld.sample.helloservice.impl.HelloServiceActivator”。
现在HelloService Bundle就可以导出HelloServiceImpl对象了。
当OSGi容器启动HelloService Bundle时,会将控制权交给HelloServiceActivator.java类,HelloServiceActivator将HelloServiceImpl对象注册为服务。
下面开始创建该服务的消费者。
(2)导入服务:
修改HelloWorld Bundle,以便让它成为HelloService服务的消费者。主要需要修改HelloWorld Bundle中的Activator.java文件。
源码如下:
importorg.osgi.framework.BundleActivator;
importorg.osgi.framework.BundleContext;
importorg.osgi.framework.ServiceReference;
importcom.javaworld.sample.service.HelloService;
publicclass Activator implements BundleActivator {
ServiceReference helloServiceReference;
public void start(BundleContext context)throws Exception {
System.out.println("HelloWorld!!");
helloServiceReference=context.getServiceReference(HelloService.class.getName());
HelloService helloService=(HelloService)context.getService(helloServiceReference);
System.out.println(helloService.sayHello());
}
public void stop(BundleContext context)throws Exception {
System.out.println("Goodbye World!!");
context.ungetService(helloServiceReference);
}
}
在上面的代码中,BundleContext.getServiceReference()方法将为注册在HelloService接口下的服务返回一个ServiceReference对象。
如果存在多个HelloService服务,该方法返回排行最高的服务(服务的排行是通过Constrains.SERVICE_RANKING属性指定)。
一旦获得ServiceReference对象,就可以调用BundleContext.getService()方法获得真实的服务对象。
参照运行Bundle的方法运行上面的示例,点击run菜单,并确保同时选中两个Bundle。当启动HelloServiceBundle时,会在控制台看到“InsideHelloServiceImpl.sayHello()”,这个消息是由HelloServiceImpl.sayHello()方法打印出来的。
(3)创建服务工厂:
在上面的示例代码中,使用OSGi框架新建一个Java对象,并把它注册为一个服务,然后让其他的Bundle来消费这个服务。在HelloServiceActivator.start()中,注意到在start()方法中新建了HelloServiceImpl的对象,然后将它注册到HelloService接口名下。代码如下:
HelloService helloService = newHelloServiceImpl();
helloServiceRegistration=context.registerService(HelloService.class.getName(), helloService, null);
这样注册后,任何其他的Bundle在请求HelloService服务时,OSGi容器将返回同一对象。
[prob]如果要为每个Bundle消费者返回不同的HelloServiceImpl对象,或者服务对象要提供的服务为一个数据库连接,但不是马上打开而是在真正需要的时候才打开这个数据库连接。这时应该如何处理?
[ans]新建一个类实现ServiceFactory接口,并把该类注册为服务,但不是注册实际的服务对象。如果完成了该步骤,其他Bundle在请求该服务时,ServiceFactory实现类将接管该请求,为每个Bundle新建一个服务对象,并把真实服务的创建时间延迟到有人真正需要该服务的时候。
A、新建工厂类HelloServiceFactory.java文件,代码如下:
public class HelloServiceFactory implements ServiceFactory{
private int usageCounter = 0;
public Object getService(Bundle bundle,ServiceRegistration registration) {
System.out.println("Create objectof HelloService for " + bundle.getSymbolicName());
usageCounter++;
System.out.println("Number ofbundles using service " + usageCounter);
HelloService helloService = newHelloServiceImpl();
return helloService;
}
public void ungetService(Bundle bundle,ServiceRegistration registration, Object service) {
System.out.println("Release objectof HelloService for " + bundle.getSymbolicName());
c210
usageCounter--;
System.out.println("Number ofbundles using service " + usageCounter);
}
}
从上面代码可以看到,ServiceFactory接口定义了两个方法:
i)getService()方法:当某一个Bundle第一次使用BundleContext.getService(ServiceReference)方法请求一个服务对象时,OSGi会调用该方法。
使用该方法可以为每一个Bundle返回不同的HelloServiceImpl对象。
若该对象不为null,OSGi会缓存这个对象,如果同一个bundle再次调用该方法,OSGi会返回同一个服务对象。
ii)ungetService()方法:当Bundle释放服务时,OSGi容器调用该方法销毁服务对象。
B、修改HelloService Bundle中的HelloServiceActivator.java的start()方法,让它注册到ServiceFactory接口名下。
publicclass HelloServiceActivator implements BundleActivator {
ServiceRegistrationhelloServiceRegistration;
public void start(BundleContext context)throws Exception {
HelloServiceFactory helloServiceFactory= new HelloServiceFactory();
helloServiceRegistration=context.registerService(HelloService.class.getName(), helloServiceFactory,null);
}
public void stop(BundleContext context)throws Exception {
helloServiceRegistration.unregister();
}
}
(4)跟踪服务:
当有多个Bundle使用同一接口名注册服务,这是OSGi容器会返回排行最高的服务,也就是注册时SERVICE_RANKING属性值最大的服务。如果有多个服务排行值相同,选择pid最小的那个服务。
如果服务消费者想了解某一接口的服务对象何时注册、何时取消注册,应该属用ServiceTracker类。
A、修改HelloWorld Bundle中的MANIFEST.MF文件,使其导入org.osgi.util.tracker包
B、新建类HelloServiceTracker.java文件,使其实现ServiceTracker类,代码如下:
public class HelloServiceTracker extends ServiceTracker {
public HelloServiceTracker(BundleContext context) {
super(context, HelloService.class.getName(),null);
}
public Object addingService(ServiceReference reference) {
System.out.println("Inside HelloServiceTracker.addingService " + reference.getBundle());
return super.addingService(reference);
}
public void removedService(ServiceReference reference, Object service) {
System.out.println("Inside HelloServiceTracker.removedService " + reference.getBundle());
super.removedService(reference, service);
}
}
在构造函数中,把HelloService接口名传入其父类中,相当于说,HelloServiceTracker应跟踪注册到HelloService接口名下的所有服务。
HelloServiceTracker继承ServiceTracker,实现了两个方法:
i)addingService()方法:当Bundle使用接口名注册服务时,该方法会被调用。
ii)removingService()方法:当Bundle取消注册某个接口名下的服务时,该方法将被调用。
C、使用HelloServiceTracker类更新Activator.java类,以便让它来管理服务,而不是直接去查找他们。
HelloService Bundle的Activator.java文件源码如下:
public class Activator implements BundleActivator {
HelloServiceTracker helloServiceTracker;
public void start(BundleContext context) throws Exception {
System.out.println("Hello World!!");
helloServiceTracker= new HelloServiceTracker(context);
helloServiceTracker.open();
HelloService helloService = (HelloService)helloServiceTracker.getService();
System.out.println(helloService.sayHello());
}
public void stop(BundleContext context) throws Exception {
System.out.println("Goodbye World!!");
helloServiceTracker.close();
}
}
在start()方法中,首先新建一个HelloServiceTracker对象,然后要求这个对象跟踪HelloService接口下的服务。可以调用getService()方法来获得HelloService对象。
可以让Bundles导出服务,而其他Bundles可以在不了解源Bundles任何信息的情况下消费这些导出的服务。
(1)导出服务:
更新HelloService Bundle,以便能把HelloServiceImpl类的对象导出为服务。(接前面的内容)
A、确认在HelloService Bundle中的MANIFEST.MF文件中导入了org.osgi.framework包
B、在HelloService Bundle中的src文件下创建一个在com.javaworld.sample.helloservice.impl包下的HelloServiceImpl.java文件,代码如下:
public class HelloServiceActivator implements BundleActivator {
ServiceRegistrationhelloServiceRegistration;
public void start(BundleContext context)throws Exception {
HelloService helloService = newHelloServiceImpl();
helloServiceRegistration=context.registerService(HelloService.class.getName(), helloService, null);
}
public void stop(BundleContext context)throws Exception {
helloServiceRegistration.unregister();
}
}
在源Bundle中,使用BundleContext.registerService()方法来导出服务,该方法有三个参数:
i)第一个参数是要注册的服务的接口名称。
如果想把服务注册到多个接口下,需要新建一个String数组存放这些接口名,然后把这个数组作为第一个参数传给registerService()方法。上面代码中,想把服务导出到HelloService接口名下。
ii)第二个参数是要注册的服务的实际JAVA对象。上面代码中,导出HelloServiceImpl类的对象,并将其作为服务。
iii)第三个参数为服务的属性,是一个Dictionary对象。如果多个Bundle导出服务的接口名相同,目标Bundle就可以使用这些属性对源进行过滤,找到感兴趣的服务。
C、最后修改HelloService Bundle中的MANIFEST.MF文件中的Bundle-Activator属性头的值,改为第二步新建文件,即“com.javaworld.sample.helloservice.impl.HelloServiceActivator”。
现在HelloService Bundle就可以导出HelloServiceImpl对象了。
当OSGi容器启动HelloService Bundle时,会将控制权交给HelloServiceActivator.java类,HelloServiceActivator将HelloServiceImpl对象注册为服务。
下面开始创建该服务的消费者。
(2)导入服务:
修改HelloWorld Bundle,以便让它成为HelloService服务的消费者。主要需要修改HelloWorld Bundle中的Activator.java文件。
源码如下:
importorg.osgi.framework.BundleActivator;
importorg.osgi.framework.BundleContext;
importorg.osgi.framework.ServiceReference;
importcom.javaworld.sample.service.HelloService;
publicclass Activator implements BundleActivator {
ServiceReference helloServiceReference;
public void start(BundleContext context)throws Exception {
System.out.println("HelloWorld!!");
helloServiceReference=context.getServiceReference(HelloService.class.getName());
HelloService helloService=(HelloService)context.getService(helloServiceReference);
System.out.println(helloService.sayHello());
}
public void stop(BundleContext context)throws Exception {
System.out.println("Goodbye World!!");
context.ungetService(helloServiceReference);
}
}
在上面的代码中,BundleContext.getServiceReference()方法将为注册在HelloService接口下的服务返回一个ServiceReference对象。
如果存在多个HelloService服务,该方法返回排行最高的服务(服务的排行是通过Constrains.SERVICE_RANKING属性指定)。
一旦获得ServiceReference对象,就可以调用BundleContext.getService()方法获得真实的服务对象。
参照运行Bundle的方法运行上面的示例,点击run菜单,并确保同时选中两个Bundle。当启动HelloServiceBundle时,会在控制台看到“InsideHelloServiceImpl.sayHello()”,这个消息是由HelloServiceImpl.sayHello()方法打印出来的。
(3)创建服务工厂:
在上面的示例代码中,使用OSGi框架新建一个Java对象,并把它注册为一个服务,然后让其他的Bundle来消费这个服务。在HelloServiceActivator.start()中,注意到在start()方法中新建了HelloServiceImpl的对象,然后将它注册到HelloService接口名下。代码如下:
HelloService helloService = newHelloServiceImpl();
helloServiceRegistration=context.registerService(HelloService.class.getName(), helloService, null);
这样注册后,任何其他的Bundle在请求HelloService服务时,OSGi容器将返回同一对象。
[prob]如果要为每个Bundle消费者返回不同的HelloServiceImpl对象,或者服务对象要提供的服务为一个数据库连接,但不是马上打开而是在真正需要的时候才打开这个数据库连接。这时应该如何处理?
[ans]新建一个类实现ServiceFactory接口,并把该类注册为服务,但不是注册实际的服务对象。如果完成了该步骤,其他Bundle在请求该服务时,ServiceFactory实现类将接管该请求,为每个Bundle新建一个服务对象,并把真实服务的创建时间延迟到有人真正需要该服务的时候。
A、新建工厂类HelloServiceFactory.java文件,代码如下:
public class HelloServiceFactory implements ServiceFactory{
private int usageCounter = 0;
public Object getService(Bundle bundle,ServiceRegistration registration) {
System.out.println("Create objectof HelloService for " + bundle.getSymbolicName());
usageCounter++;
System.out.println("Number ofbundles using service " + usageCounter);
HelloService helloService = newHelloServiceImpl();
return helloService;
}
public void ungetService(Bundle bundle,ServiceRegistration registration, Object service) {
System.out.println("Release objectof HelloService for " + bundle.getSymbolicName());
c210
usageCounter--;
System.out.println("Number ofbundles using service " + usageCounter);
}
}
从上面代码可以看到,ServiceFactory接口定义了两个方法:
i)getService()方法:当某一个Bundle第一次使用BundleContext.getService(ServiceReference)方法请求一个服务对象时,OSGi会调用该方法。
使用该方法可以为每一个Bundle返回不同的HelloServiceImpl对象。
若该对象不为null,OSGi会缓存这个对象,如果同一个bundle再次调用该方法,OSGi会返回同一个服务对象。
ii)ungetService()方法:当Bundle释放服务时,OSGi容器调用该方法销毁服务对象。
B、修改HelloService Bundle中的HelloServiceActivator.java的start()方法,让它注册到ServiceFactory接口名下。
publicclass HelloServiceActivator implements BundleActivator {
ServiceRegistrationhelloServiceRegistration;
public void start(BundleContext context)throws Exception {
HelloServiceFactory helloServiceFactory= new HelloServiceFactory();
helloServiceRegistration=context.registerService(HelloService.class.getName(), helloServiceFactory,null);
}
public void stop(BundleContext context)throws Exception {
helloServiceRegistration.unregister();
}
}
(4)跟踪服务:
当有多个Bundle使用同一接口名注册服务,这是OSGi容器会返回排行最高的服务,也就是注册时SERVICE_RANKING属性值最大的服务。如果有多个服务排行值相同,选择pid最小的那个服务。
如果服务消费者想了解某一接口的服务对象何时注册、何时取消注册,应该属用ServiceTracker类。
A、修改HelloWorld Bundle中的MANIFEST.MF文件,使其导入org.osgi.util.tracker包
B、新建类HelloServiceTracker.java文件,使其实现ServiceTracker类,代码如下:
public class HelloServiceTracker extends ServiceTracker {
public HelloServiceTracker(BundleContext context) {
super(context, HelloService.class.getName(),null);
}
public Object addingService(ServiceReference reference) {
System.out.println("Inside HelloServiceTracker.addingService " + reference.getBundle());
return super.addingService(reference);
}
public void removedService(ServiceReference reference, Object service) {
System.out.println("Inside HelloServiceTracker.removedService " + reference.getBundle());
super.removedService(reference, service);
}
}
在构造函数中,把HelloService接口名传入其父类中,相当于说,HelloServiceTracker应跟踪注册到HelloService接口名下的所有服务。
HelloServiceTracker继承ServiceTracker,实现了两个方法:
i)addingService()方法:当Bundle使用接口名注册服务时,该方法会被调用。
ii)removingService()方法:当Bundle取消注册某个接口名下的服务时,该方法将被调用。
C、使用HelloServiceTracker类更新Activator.java类,以便让它来管理服务,而不是直接去查找他们。
HelloService Bundle的Activator.java文件源码如下:
public class Activator implements BundleActivator {
HelloServiceTracker helloServiceTracker;
public void start(BundleContext context) throws Exception {
System.out.println("Hello World!!");
helloServiceTracker= new HelloServiceTracker(context);
helloServiceTracker.open();
HelloService helloService = (HelloService)helloServiceTracker.getService();
System.out.println(helloService.sayHello());
}
public void stop(BundleContext context) throws Exception {
System.out.println("Goodbye World!!");
helloServiceTracker.close();
}
}
在start()方法中,首先新建一个HelloServiceTracker对象,然后要求这个对象跟踪HelloService接口下的服务。可以调用getService()方法来获得HelloService对象。
相关文章推荐
- OSGi服务:非常适合SOA的架构
- OSGi服务:非常适合SOA的架构
- OSGi服务:非常适合SOA的架构
- OSGi服务:非常适合SOA的架构
- 软件架构设计系列总结—5—SOA面向服务架构简述
- 软件架构设计系列总结—5—SOA面向服务架构简述
- OSGi服务:SOA的架构
- 面向服务体系架构的业务规划和建模方法系列之三--SOA方法裁减样例 推荐
- 面向服务体系架构的业务规划和建模方法系列之五——SOA项目中IBM产品的采用 推荐
- 面向服务的体系架构(SOA)
- Windows 网络服务架构系列课程详解(四) --- DNS高级技术配置详解 推荐
- SOA面向服务架构——SOA的概念
- 我的WCF之旅(5):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的重载(Overloading)
- SOA体系架构 实现多种空管信息综合服务
- Atitit.架构设计趋势 设计模式 ---微服务架构 soa
- BEA的SOA服务基础架构解决方案
- 微服务与SOA架构
- 微服务架构模式系列文章之八:第三方注册
- 基于面向服务体系架构(SOA)和面向资源体系架构(ROA)的业务组件模型