OSGi认识

OSGi认识

内容源自Hello,osgi

osgi, java语言的动态模块系统,它为模块化应用开发定义了一套基础架构。基于osgi的开源容器框架有:Knoflerfish、Equinox和Apache Felix.通过这些容器,可以把应用程序分成多个模块单元,如此更容易管理各个模块单元之间的交叉依赖关系。

OSGi优点

  • 在不重启容器的情况下,可以对应用程序中的不同模块进行安装、卸载、启动和停止。

  • 容器可以同时运行应用程序中某一模块的多个版本

  • osgi为开发嵌入式应用、移动应用、富互联网应用提供了优秀的基础架构

一、创建OSGi bundle

在eclipse上创建com.javaworld.sample.helloworld的osgi bundle

  1. New Project --> Plug-in Project

  2. Project Name: com.javaworld.sample.helloworld, an OSGi framework 选择standard,其他项默认

  3. Templates 选择Hello OSGi Bundle,结束。

    1. 启动配置 Run Configuration

在这里插入图片描述

Bundles:

  • Workspace勾选默认com.javaworld.sample.helloworld(1.0.0.qualifier)

  • Target Platform勾选以下

org.apache.felix.gogo.command
org.apache.felix.gogo.runtime
org.apache.felix.gogo.shell
org.eclipse.equinox.console
org.eclipse.osgi         #前四个不选会报异常

Arguments: 在后面补充 -clean

-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean

5.启动后,控制台无报错,输入ss成功显示相关bundle.
在这里插入图片描述

注:按照以上第四点操作不会出现Root exception: Workbench has not been created yet.

org.osgi.framework.BundleException: Could not find bundle: org.eclipse.equin等报错

OSGi 规定的bundle 命令

ss 显示所有已安装的bundles及其状态、id;

start 启动某个bundle

stop 停止某个bundle

update 使用新的jar更新某个bundle

install 安装新的bundle

uninstall 卸载某个已安装的bundle

二、OSGi 依赖性管理:访问域

Bundle 中类的默认访问范围仅对Bundle内部可见,对其他Bundle是不可见。那么如何从一个Bundle访问另外一个Bundle类呢?解决方法是将源Bundle中的包导出来,然后把它们导入到目标Bundle中。

同样创建com.javaworld.sample.service Bundle

1.新建com.javaworld.sample.service.HelloService.java 接口

package com.javaworld.sample.service;
public interface HelloService {

    public String sayHello();
}

2.新建com.javaworld.sample.service.impl.HelloServiceImpl.java类,实现HelloService接口

package com.javaworld.sample.service.impl;
import com.javaworld.sample.service.HelloService;

public class HelloServiceImpl implements HelloService{

    @Override
    public String sayHello() {
        System.out.println("InsideHelloServiceImple.sayHello()");  
        return"Say Hello";  
    }

}

3.导出java包: com.javaworld.sample.service

双击MANIFEST.MF文件进行操作

在这里插入图片描述

4.导入java包:project com.javaworld.sample.helloworld导入 包com.javaworld.sample.service

在这里插入图片描述

此时,打开com.javaworld.sample.helloworldActivator.java,此时可以导入com.javaworld.sample.service与com.javaworld.sample.service.impl包。但实际com.javaworld.sample.helloworld能访问的只有com.javaworld.sample.service,无法访问com.javaworld.sample.service.impl.

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三、OSGi 服务:适合实现面向服务SOA

它可以让Bundles导出服务,而其它的Bundles可以在不必了解源Bundles任何信息的情况下消费这些导出的服务。由于OSGi具有隐藏真实的服务实现类的能力,所以它为面向服务的应用提供了良好的类与接口的组合。

在OSGi框架中,源Bundle在OSGi容器中注册POJO对象,该对象不必实现任何接口,也不用继承任何超类,但它可以注册在一个或多个接口下,并对外提供服务。目标Bundle可以向OSGi容器请求注册在某一接口下的服务,一旦它发现该服务,目标Bundle就会将该服务绑定到这个接口,并能调用该接口中的方法。

上面的二、中提到HelloServiceImpl服务实现类无法访问,可以利用OSGi的导出服务,提供给HelloWorld bundle使用.

  1. 导出服务

    在HelloService Bundle 中新建HelloServiceActivator.java,注册HelloService接口,对外提供服务。

package com.javaworld.sample.service.impl;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;   
import org.osgi.framework.ServiceRegistration;  
import com.javaworld.sample.service.HelloService;

public class HelloServiceActivator implements BundleActivator{
   ServiceRegistration helloServiceRegistration;
   @Override
   public void start(BundleContext arg0) throws Exception {
       // TODO Auto-generated method stub
       System.out.println("Hello,HelloService!");

       HelloService helloService = new HelloServiceImpl();
       helloServiceRegistration=arg0.registerService(HelloService.class.getName(), helloService, null);
   }

   @Override
   public void stop(BundleContext arg0) throws Exception {
       // TODO Auto-generated method stub
       System.out.println("Good Bye! Hello Service!");
       helloServiceRegistration.unregister();
   }
}

注:使用BundleContext.registerService()方法导出服务。
此方法第一个参数: 存放接口名,如果有多个接口,先存放于新建数组中,再将此数组放在此参数;
第二个参数为实现服务类对应的Java对象;第三个参数为服务属性,是一个dictionary对象,当有多个导出服务的接口名相同时,利用此属性进行筛选。
编辑HelloService Bundle的MANIFEST文件将Bundle-Activator的值设为
Bundle-Activator: com.javaworld.sample.service.impl.HelloServiceActivator

  1. 导入服务

    让HelloWorld Bundle成为HelloService 的服务消费者,修改Activator.java

package com.javaworld.sample.helloworld;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import com.javaworld.sample.service.*;
import com.javaworld.sample.service.impl.*;

public class Activator implements BundleActivator{

    /*
     * (non-Javadoc)
     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
     */

    ServiceReference helloServiceReference;
    public void start(BundleContext context) throws Exception {
        System.out.println("Hello World!!");
        helloServiceReference = context.getServiceReference(HelloService.class.getName());
        HelloService helloService = context.getService(helloServiceReference);
        System.out.println(helloService.sayHello());
    }

    /*
     * (non-Javadoc)
     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
     */
    public void stop(BundleContext context) throws Exception {
        System.out.println("Goodbye World!!");
        context.ungetService(helloServiceReference);
    }
}

通过BundleContext.getServiceReference()方法返回一个ServiceReference对象(如果存在多个服务,返回排名最高的服务,服务排行由Constants.SERVICE_RANKING属性指定)。之后通过BundleConetxt.getService(ServiceReference)方法获取到注册好的真实服务。

此时运行HelloService Bundle,通过控制台输出可以看到已成功访问HelloServiceImpl实现类的方法。

在这里插入图片描述

在这里插入图片描述

3.创建服务工厂

<1>新建HelloServiceFactory类,实现org.osgi.framework.ServiceFactory接口,接口定义了两个方法:

  • getService():某个bundle使用BundleContext.getService(ServiceReference)请求服务对象时,OSGi框架会调用到该方法。这个方法为每个Bundle新建并返回不同的HelloServiceImpl对象,如果这个对象不是null,OSGi框架会缓存这个对象。如果同一个Bundle再次调用BundleContext.getService(ServiceReference)方法,OSGi将返回同一个服务对象。

  • ungetService()`方法:当Bundle释放服务时,OSGi容器可以调用该方法销毁服务对象。

    在下面源代码中,使用usageCounter变量来跟踪服务的使用数目,并打印出该服务的客户端数量。

package com.javaworld.sample.helloservice;

import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceRegistration;

import com.javaworld.sample.service.HelloService;
import com.javaworld.sample.service.impl.HelloServiceImpl;

public class HelloServiceFactory implements ServiceFactory{

    private int usageCounter=0;
    @Override
    public Object getService(Bundle bundle, ServiceRegistration registration) {
        // TODO Auto-generated method stub
        System.out.println("Create objectof HelloService for " + bundle.getSymbolicName());  
        usageCounter++;  
        System.out.println("Number of bundles using service " + usageCounter);  
        HelloService helloService = new HelloServiceImpl();  
        return helloService;  
    }

    @Override
    public void ungetService(Bundle bundle, ServiceRegistration registration,
            Object service) {
        // TODO Auto-generated method stub
        System.out.println("Release objectof HelloService for " + bundle.getSymbolicName());  
        usageCounter--;  
        System.out.println("Number of bundles using service " + usageCounter);  
    }

}

<2>修改HelloServiceActivatorstart()方法,让其注册到ServiceFactory接口下。

package com.javaworld.sample.service.impl;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceRegistration;

import com.javaworld.sample.helloservice.HelloServiceFactory;
import com.javaworld.sample.service.HelloService;


public class HelloServiceActivator implements BundleActivator{    

    ServiceRegistration helloServiceRegistration;
    @Override
    public void start(BundleContext bc) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("Hello,HelloService!");
//        HelloService helloService = new HelloServiceImpl();    //对比下,这是2.导入服务中的HelloService接口注册

//        helloServiceRegistration=bc.registerService(HelloService.class.getName(), helloService, null);                
        ServiceFactory helloServiceFactory=new HelloServiceFactory();
        helloServiceRegistration=bc.registerService(HelloService.class.getName(), helloServiceFactory, null);
    }

    @Override
    public void stop(BundleContext arg0) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("Good Bye! Hello Service!");
        helloServiceRegistration.unregister();
    }
}

<3>HelloWorld bundle的Activator.java与2中的不变。

运行HelloServiceBundle 发现,HelloWorld Bundle也启动并调用注册的服务,计数加1。stop 13关闭HelloWorld bundle时,释放HelloServiceBundle服务,计数变为0.

在这里插入图片描述

  1. 跟踪服务

<1>新建HelloService Tracker Bundle,对应Projectcom.osgi.util.tracker,关联com.javaworld.sample.service

<2>新建HelloServiceTracker.java,如下:

package com.osgi.util.tracker;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import com.javaworld.sample.service.HelloService;


public class HelloServiceTracker extends ServiceTracker{

    public HelloServiceTracker(BundleContext context) {
        super(context, HelloService.class, null);
        // TODO Auto-generated constructor stub
    }

    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.removeService"+reference.getBundle());
        super.removedService(reference, service);
    }
}

构造方法将HelloService接口名传入父类中,此时HelloServiceTracker跟踪注册到HelloService下的所有服务。addingService方法在Bundle使用接口注册的服务时被调用

removedService方法在Bundle取消接口注册服务时被调用

<3>修改HelloServiceTracker bundleActivator.java,如下:

package com.osgi.util.tracker;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import com.javaworld.sample.service.HelloService;

public class Activator implements BundleActivator {

    /*
     * (non-Javadoc)
     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
     */
    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());
    }

    /*
     * (non-Javadoc)
     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
     */
    public void stop(BundleContext context) throws Exception {
        System.out.println("Goodbye World!!");         
        helloServiceTracker.close();  
    }

}

start()方法中新建了``HelloServiceTracker对象,要求跟踪HelloService中注册的服务。Trcker调用其getService()方法可获得HelloService对象。

注:上面的Tracker Bundle也可不创建,直接在HelloWorld Bundle中增加并修改其Activator.java亦可。

<3>运行 HelloService Bundle,start 14,16将调用到HelloServiceTracker的addingService方法,stop 14,16将调用到HelloServiceTracker的removedService方法

Hello,HelloService!
Hello World!!
Inside HelloServiceTracker.addingServicecom.javaworld.sample.service_1.0.0.qualifier [12]
Create objectof HelloService for com.osgi.util.tracker
Number of bundles using service 1
InsideHelloServiceImple.sayHello()
Say Hello
Hello World!!
Create objectof HelloService for com.javaworld.sample.helloworld
Number of bundles using service 2
InsideHelloServiceImple.sayHello()
Say Hello
osgi> ss
"Framework is launched."


id    State       Bundle
0    ACTIVE      org.eclipse.osgi_3.10.1.v20140909-1633
2    ACTIVE      org.apache.felix.gogo.shell_0.10.0.v201212101605
3    ACTIVE      org.eclipse.equinox.console_1.1.0.v20140131-1639
5    ACTIVE      org.apache.felix.gogo.runtime_0.10.0.v201209301036
6    ACTIVE      org.apache.felix.gogo.command_0.10.0.v201209301215
12    ACTIVE      com.javaworld.sample.service_1.0.0.qualifier
14    ACTIVE      com.osgi.util.tracker_1.0.0.qualifier
16    ACTIVE      com.javaworld.sample.helloworld_1.0.0.qualifier
osgi> stop 16
Goodbye World!!
Release objectof HelloService for com.javaworld.sample.helloworld
Number of bundles using service 1
osgi> stop 14
Goodbye World!!
Inside HelloServiceTracker.removeServicecom.javaworld.sample.service_1.0.0.qualifier [12]
Release objectof HelloService for com.osgi.util.tracker
Number of bundles using service 0
osgi>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值