前言
什么是服务,简单的说就是把一件事情交给别人去做(服务提供者),至于别人如何去 对应调用者(服务使用者)来说是不care的。在现实世界中 服务使用者(客户),只关心结果是什么,而不关心过程;比如客户点了一个芝士披萨,餐厅如何去做这个披萨客户不会去过问(过程),客户只管最后的披萨是否好吃(结果),在程序设计的世界中也是如此。
服务化或者微服务化,本质上就是对一组服务按业务进行分类封装,并进行独立部署,这是构建分布式系统的基础。服务化可以实现系统之间的解耦:核心业务逻辑都在各自系统内部完成,有些工作需要使用外部协助时,只需要根据一定协议调用外部服务即可。这种松耦合的关系,还可以实现服务的热插拔;另外服务不可用时,也可以方便的采取一些兜底措施。
对于一个大型电商网站系统的设计也是如此,该系统一般会由成百上千个子系统构成,这些子系统各自处理自己内部的核心业务,当需要其他子系统协助时,通过调用服务接口即可。如此,各个系统可以独自并行开发和维护,并且所有的服务只需要开发一次就可以在多个子系统中复用。这就是涉及到公司级的SOA服务治理,一般都会采用成熟的服务治理框架来完成,以现在流行的RPC服务治理框架为例,服务框架一般分为:服务提供者、服务注册中心、服务使用者,如下:
好了 打住 关于服务就不扯远了,这跟今天的主题OSGI服务层有什么关系呢?其实OSGI服务层的作用跟SOA服务治理框架的作用完全一样,而且设计思想也几乎是一样的,都是按照上图的三个角色以及关系进行设计的。唯一不同的时:SOA服务治理面向的公司级服务治理,而OSGI服务层面向的是单个JVM实例内部服务治理,也就是普通服务化的缩小版。
OSGI服务层
为什么要在JVM内部还要实现服务化呢?其实原因与公司级服务化的目的类似:
可以实现多个模块的完全解耦(高内聚低耦合模块),实现一个由多个松耦合模块(Bundle)构建起的单个系统;
实现服务的热插拔,与普通SOA服务治理一样,OSGI框架可以在其内部实现服务的热更新、热替换(换另外一种实现);
并行开发,在项目组内部可以提前把单个系统拆分成多个模块(Bundle),定义好各个模块之间的边界协议(接口,或者说服务),由不同的开发人员并行开发,他们只需要专注自己负责的模块即可。想想就是一件令人兴奋的事,下面就开始来看看OSGI规范是如何定义的服务层API,自己我们如何去使用这些API。服务层的API定义在上下文BundleContext中:
public interface BundleContext extends BundleReference { //添加服务监听器 void addServiceListener(ServiceListener var1, String var2) throws InvalidSyntaxException; //添加服务监听器 void addServiceListener(ServiceListener var1); //取消服务监听器 void removeServiceListener(ServiceListener var1); //注册服务 ServiceRegistration<?> registerService(String[] var1, Object var2, Dictionary<String, ?> var3); //注册服务 ServiceRegistration<?> registerService(String var1, Object var2, Dictionary<String, ?> var3); //注册服务 <S> ServiceRegistration<S> registerService(Class<S> var1, S var2, Dictionary<String, ?> var3); //获取服务引用 ServiceReference<?>[] getServiceReferences(String var1, String var2) throws InvalidSyntaxException; //获取服务引用 ServiceReference<?>[] getAllServiceReferences(String var1, String var2) throws InvalidSyntaxException; //获取服务引用 ServiceReference<?> getServiceReference(String var1); //获取服务引用 <S> ServiceReference<S> getServiceReference(Class<S> var1); //获取服务引用 <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> var1, String var2) throws InvalidSyntaxException; //获取服务对象 <S> S getService(ServiceReference<S> var1); //取消服务对象 boolean ungetService(ServiceReference<?> var1); //省略其它生命周期层方法 }
纵观这些API,大致可以归为3类:注册服务方法、获取服务方法、监听器相关方法。
注册服务方法
OSGI框架提供了几个重载的注册服务方法,其作用就是发布服务到“注册中心”。发布一个服务很简单:
public class HelloWorldAtivictor implements BundleActivator{ @Override public void start(BundleContext context) throws Exception { Dictionary dictionary = new Properties(); dictionary.put("test","test"); ServiceRegistration registration = context.registerService(HelloService.class.getName(),new HelloServiceImpl("小明"),dictionary); dictionary.put("test","test2"); registration.setProperties(dictionary);//修改元数据 System.out.println("start server bundle"); registration.unregister();//取消服务注册 } @Override public void stop(BundleContext context) throws Exception { System.out.println("stop"); } }
本示例中使用的注册方法有三个参数:第一个是服务的名字(一般是接口名),第二个是服务的具体实现对象,第三个是元数据主要用来区分同一个接口发布成不同的实现服务,客户端可以根据条件筛选自己需要的服务。
服务注册成功后会返回一个ServiceRegistration对象,这个对象是Bundle内部私有的。可以通过调用其setProperties方法修改元数据;以及unregister方法取消服务注册,在Bundle停止时,框架会自动清理所有的该Bundle注册的服务,所以一般情况下不需要我们手动去取消服务注册。
获取服务方法
获取一个OSGI服务,需要两步 第一步通过上下文的getServiceReference方法 从注册中心获取注册引用:
public class ClientActivator implements BundleActivator { @Override public void start(BundleContext context) throws Exception { ServiceReference ref = context.getServiceReference(HelloService.class.getName()); if(ref!=null){ try{ HelloService helloService = ((HelloService)context.getService(ref)); if(helloService!=null){//调用服务方法 helloService.sayHello(); } }catch (Exception e){ System.out.println("服务调用异常"); } finally { context.ungetService(ref); } } System.out.println("start client bundle"); } @Override public void stop(BundleContext context) throws Exception { } }
第二步,调用上下文对象的getService方法获取到真实的服务引用,然后就可以调用服务接口中定义的方法了:
HelloService helloService = ((HelloService)context.getService(ref)); helloService.sayHello();
由于在OSGI框架下所有的服务都有可能随时消失,注意开发时需要进行适当的空值判断。另外由于getService方法获取的是提供服务Bundle中的一个真实引用,尽量不要长期持有,否则服务Bundle在需要停止时,无法正常的进行拉结回收(因为还在被其他对象引用)。在使用完服务后最好手动调用ungetService方法告诉注册中心释放引用。
监听器相关方法
由于OSGI框架中的服务有可能随时消失或者更新,前面提到了尽量不要长期持有一个对象,这势必会导致每次在使用时都需要重复取服务。如果有一种方式能在服务发生变化是通知服务使用方,同步进行更新,这样就可以解脱出来了。OSGI服务层的服务层中定义了监听器注册机制(ServiceListener),来解决这个问题。
服务的状态变化一般有三种:注册、更新、注销。也就是说监听器 需要监听这三种变化,并通知服务使用者做出响应。首先来看一个简单的监听器实现:
public class HelloListener implements ServiceListener { private BundleContext context; public HelloListener(BundleContext context) { this.context = context; } public void serviceChanged(ServiceEvent event) { switch (event.getType()) { case ServiceEvent.REGISTERED: Object service = context.getService(event.getServiceReference()); if(service instanceof HelloService){ ClientActivator.helloService = (HelloService) context.getService(event.getServiceReference()); } break; case ServiceEvent.MODIFIED: break; case ServiceEvent.UNREGISTERING: service = context.getService(event.getServiceReference()); if(service instanceof HelloService){ context.ungetService(event.getServiceReference()); ClientActivator.helloService = null; } break; default: break; } } }
主要就是实现serviceChanged方法,它有一个ServiceEvent类型参数,用于接收当前的变更类型。每当接收到变化时就可以更新helloService对象,当服务消失时把helloService置为null。这个对象就可以被放到一个对象的成员变量里(本示例是一个静态常量里),方便复用。如果有多个可用的服务,可以把这些服务对象放到一个集合中,根据业务需要使用不同的服务对象。
监听器定义完成后,还需要把它注册到一个服务下,注册服务监听器一般在启动器中完成:
public class ClientActivator implements BundleActivator { public static volatile HelloService helloService;//服务对象 private ExecutorService executorService; @Override public void start(BundleContext context) throws Exception { System.out.println("client开始启动"); //注册监听器 HelloListener listener = new HelloListener(context); context.addServiceListener(listener); //这里可以启动一个线程测试HelloService服务是否可用 executorService = Executors.newSingleThreadExecutor(); executorService.submit(new TestTask(context)); } @Override public void stop(BundleContext context) throws Exception { executorService.shutdown();//优雅的关闭线程池 } } //模拟测试helloService服务 public class TestTask implements Runnable{ private BundleContext context; public TestTask(BundleContext context) { this.context = context; } @Override public void run() { boolean flag = true; while (flag){ try { if (ClientActivator.helloService != null) { ClientActivator.helloService.sayHello(); } else { System.out.println("没有可用的服务"); } }catch (Exception e){ System.out.println("业务异常"); } //睡5秒重试 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("线程池关闭"); flag = false; } } } }
注册一个服务监听器很简单,只需要调用Bundle上下文对象的addServiceListener方法即可。当服务提供方注册服务到注册中心时,就可以自动触发对静态的成员变量helloService进行赋值。当服务提供方取消服务注册时,会自动触发对静态的成员变量helloService置空。
可见自己实现服务监听器是件比较麻烦的工作,OSGI提供了服务追踪ServiceTracker对服务监听进行了封装,使用起来更简单,而且不容易出错。
服务追踪器ServiceTracker
使用ServiceTracker跟踪服务,无需自己实现服务监听器,使用方式很简单:ServiceTracker有两个构造函数,调用构造函数创建追踪器对象,并调用其open方法开启追踪即可:
public class TrackerActivator implements BundleActivator { private ServiceTracker serviceTracker; private ExecutorService executorService; @Override public void start(BundleContext context) throws Exception { serviceTracker = new ServiceTracker(context, HelloService.class.getName(), null); serviceTracker.open();//打开追踪器 //新开一个线程,模拟调用服务 executorService = Executors.newSingleThreadExecutor(); executorService.submit(new TestTask(serviceTracker)); System.out.println("start tracker bundle"); } @Override public void stop(BundleContext context) throws Exception { serviceTracker.close();//关闭追踪器 executorService.shutdown(); } } //模式测试服务 public class TestTask implements Runnable{ public ServiceTracker serviceTracker; public TestTask(ServiceTracker serviceTracker) { this.serviceTracker = serviceTracker; } @Override public void run() { boolean flag = true; while (flag){ try { HelloService helloService = (HelloService)serviceTracker.getService(); if (helloService!= null) { helloService.sayHello(); } else { System.out.println("没有可用的服务"); } }catch (Exception e){ System.out.println("业务异常"); } //睡5秒重试 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("线程池关闭"); flag = false; } } } }
上面模拟代码比较长,但对于使用追踪器来说,只有三行代码:
ServiceTracker serviceTracker = new ServiceTracker(context, HelloService.class.getName(), null); serviceTracker.open();//打开追踪器 //获取服务 HelloService helloService = (HelloService)serviceTracker.getService();
创建追踪器对象-->开启追踪器-->调用最终器的getService()方法获取服务对象 即可。使用ServiceTracker追踪一个服务就这么简单。
另外ServiceTracker的构造方法第三个参数可以传入一个“定制器”对象,上述示例中传入的是null,即非定制模式。接下来看下定制模式,首先就要创建一个定制器 实现ServiceTrackerCustomizer接口即可,这个接口定义了三个方法:
public interface ServiceTrackerCustomizer<S, T> { //添加服务 T addingService(ServiceReference<S> var1); //修改服务 void modifiedService(ServiceReference<S> var1, T var2); //移除服务 void removedService(ServiceReference<S> var1, T var2); }
“定制器”的作用是在服务发生变化时(注册服务、修改服务、移除服务)可以打印一些日志,或者做一些保证等之定义操作,创建一个自己的“定制器”类,实现这个接口:
public class MyServiceTrackerCustomizer implements ServiceTrackerCustomizer { private BundleContext context; public MyServiceTrackerCustomizer(BundleContext context) { this.context = context; } @Override public Object addingService(ServiceReference serviceReference) { HelloService helloService = (HelloService)context.getService(serviceReference); //返回一个包装后的服务 return new MyHelloService(helloService); } @Override public void modifiedService(ServiceReference serviceReference, Object o) { System.out.println("服务被修改了"); } @Override public void removedService(ServiceReference serviceReference, Object o) { System.out.println("服务被移除了"); } } class MyHelloService implements HelloService{ private HelloService helloService; public MyHelloService(HelloService helloService) { this.helloService = helloService; } @Override public void sayHello() { System.out.println("包装服务开始"); helloService.sayHello(); System.out.println("包装服务结束"); } }
这个定制器,在发现有服务注册时,使用了一个装饰器对服务进行了包装;在服务修改或者移除时,打印一条日志信息。使用带定制器的 服务追踪器 很简单,把定制器传入ServiceTracker构造方法第三个参数即可:
ServiceTracker serviceTracker = new ServiceTracker(context, HelloService.class.getName(), new MyServiceTrackerCustomizer(context));
总的来说使用服务追踪器比自己定义服务监听器 使用起来更简单,而且不容易出错(但一定要启动opne和close追踪器)。
关于OSGI服务层相关的API就总结到这里,至此已经对OSGI的模块层、生命周期层、服务层分别进行了总结。但示例比较少,下次准备做一个完整的demo,并使用idea开发工具进行讲解。
相关推荐
OSGi(Open Service Gateway Initiative)是一个Java社区定义的模块化服务平台,它允许在同一个运行环境中部署多个版本的同一个...对于需要高度模块化、动态更新和维护的应用程序,OSGi服务层是一个非常有价值的工具。
OSGi(Open Services Gateway Initiative)是一个基于Java语言的服务平台,提供了一种动态化、模块化的应用程序架构。在OSGi架构中,整个生命周期管理是十分重要的组成部分,它保证了应用能够动态地进行安装、启动、...
1. **运行环境**:基础的执行环境,支持OSGi服务的运行。 2. **安全层**:基于Java的安全机制,确保模块间的操作安全。 3. **模块层**:定义了Bundle的结构和交互方式,包括Import Package、Export Package、...
OSGi核心技术文档详细介绍了OSGi的三个模块层次:服务层、模块层和生命周期层。 服务层是OSGi最上层的抽象,负责定义和实现所有服务的生命周期。在OSGi中,服务是指一组具有明确目的的代码和数据的集合,例如日志...
OSGi服务层是框架中负责服务注册和服务请求的层次。在OSGi中,服务是注册到框架中的Java对象,可以设置Service的属性,并在需要时通过属性查找和获取服务。 OSGi框架支持懒加载模式,即只有在实际有请求发生时,...
OSGi框架从概念上可以分为三个层次:模块层、生命周期层和服务层。 模块层是OSGi框架中最基础的部分。它的主要功能是处理包和共享代码。模块化在OSGi中是通过为Jar包添加元数据(metadata)来实现的。元数据定义了...
4. **服务层**:服务注册是OSGI的一个关键特性,它允许动态的协作和资源共享。bundles可以通过服务注册来共享对象,而不是直接通过类共享,这样可以更好地适应动态的安装和卸载。相关的实现集中在serviceReference.h...
服务层是OSGi中最活跃的部分,它支持基于服务的编程模型。在这个模型中,组件通过发布和消费服务来进行交互。服务是一个接口,可以被任何需要它的bundle使用。服务注册和查找是在运行时动态进行的,这使得系统能够...
这样,Spring-DM会自动管理这些服务的生命周期,并使得其他bundle可以通过OSGi服务发现机制找到并使用它们。 总的来说,基于OSGi和Spring的Web应用开发结合了两者的优点:OSGi提供了模块化和动态部署的能力,而...
在OSGi中,Spring可以作为服务注册和查找的平台,通过OSGi服务注册表来发现和管理其他服务,同时Spring的Bean可以在各个bundle之间共享。 3. **Hibernate**:Hibernate是一个对象关系映射(ORM)框架,简化了数据库...
### OSGi服务平台核心规范知识点解析 #### 核心概念与定义 **OSGi (Open Service Gateway Initiative)** 是一个为 Java 定义模块化系统的框架。它支持将应用程序和服务分解为可重用的组件,并在运行时动态安装、...
- 依赖注入:利用OSGi的服务发现机制,动态获取并使用Hibernate服务。 - 数据源管理:在OSGi环境中配置数据源,确保其能在多个模块间共享。 5. **挑战与解决方案**:集成过程中可能遇到的问题,比如类加载冲突、...
OSGi服务平台规范4.1是其第四个版本,由OSGi成员公司共同开发,扩展了原有的API并修复了部分问题,以确保与早期版本的兼容性。 **OSGi框架概述** OSGi核心规范4.1提供了基础框架,支持动态部署和管理称为bundle的...
- **L3层(系统服务)**:OSGi提供了一些系统级别的服务,例如权限管理和启动级别控制等。 #### 三、OSGi全栈 OSGi不仅是一个简单的模块化框架,还提供了一个完整的生态系统。其中包括了: - **权限管理**:通过`...
- 使用Spring配置文件(`computeAdd-context.xml` 和 `computeMultiply-context.xml`)将这两个实现注册为OSGi服务。 **步骤2:实现Web层** 1. **Web层(bundle com.zxn.example.web):** - 使用Spring MVC框架来...