`

OSGi (第一部分): Bundles入门(续,翻译)(转)

    博客分类:
  • OSGI
阅读更多

4. 依赖性管理
OSGi允许您把您的应用程序分成多个模块,并能管理这些模块之间的依赖性。为了达到这个目的,它引入了Bundle访问域的概念。Bundle中类的缺省访问范围只对本Bundle内部可见,但对其它任何Bundle都是不可见的;在Bundle内部,类的可访问性遵循Java语言的一般规范。那么,您如果想要从一个Bundle中访问另一个Bundle中的类,您应该怎么办呢?解决方法是将源Bundle中的包导出来,然后把它们导入到目标Bundle中。在本小结中,我们将通过一个示例程序说明这个概念。
首先,我们新建一个名com.javaworld.sample.HelloServiceBundle,并从其中导出一个包,然后将该包导入到我们的com.javaworld.sample.HelloWorld Bundle中。
4.1. 导出Java
我们开始新建一个com.javaworld.sample.HelloServiceBundle,并从其中导出一个Java包,具体步骤如下:
1) 新建com.javaworld.sample.HelloService Bundle,具体步骤请参见上小节中新建com.javaworld.sample.HelloWorldBundle的步骤;
2) HelloService Bundle中,新建一个com.javaworld.sample.service.HelloService.java接口,其源代码如清单3所示。

源代码清单3. HelloService.java

Java代码 复制代码 收藏代码
  1. package com.javaworld.sample.service;   
  2. public interface HelloService {   
  3. public String sayHello();   
  4. }  
package com.javaworld.sample.service;
public interface HelloService {
public String sayHello();
}

 

3) 新建类com.javaworld.sample.service.impl.HelloServiceImpl.java,该类实现HelloService接口,其源代码如清单4所示。

源代码清单4. HelloServiceImpl.java

Java代码 复制代码 收藏代码
  1. package com.javaworld.sample.service.impl;   
  2. import com.javaworld.sample.service.HelloService;   
  3. public class HelloServiceImpl implements HelloService {   
  4. public StringsayHello() {   
  5. System.out.println("InsideHelloServiceImple.sayHello()");   
  6. return"Say Hello";   
  7. }   
  8. }  
package com.javaworld.sample.service.impl;
import com.javaworld.sample.service.HelloService;
public class HelloServiceImpl implements HelloService {
public StringsayHello() {
System.out.println("InsideHelloServiceImple.sayHello()");
return"Say Hello";
}
}

 
4) 请在您的Eclipse Manifest编辑器中打开HelloService包中的MANIFEST.MF文件,点击“Runtime(运行时) 标签,在“导出包”小节,单击“Add(添加)”按钮,并选择com.javaworld.sample.service包。这时,HelloServiceBundle中的MANIFEST.MF文件代码应如源代码清单5所示。

源代码清单5. HelloService Bundle中的Manifest文件
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: HelloService Plug-in
Bundle-SymbolicName:com.javaworld.sample.HelloService
Bundle-Version: 1.0.0
Bundle-Vendor: JAVAWORLD
Bundle-Localization: plugin
Export-Package: com.javaworld.sample.service
Import-Package:org.osgi.framework;version="1.3.0"

您可以看到,HelloService Bundle中的MANIFEST.MF文件和HelloWorldBundle非常相似,唯一的区别就是多了一个Export-Package属性头,该属性头的值为com.javaworld.sample.serviceExport-Package属性头通知OSGi容器,其它Bundle可以从HelloService Bundle外面访问com.javaworld.sample.service包中的类。请注意,在示例代码中,我们只暴露了接口类HelloService,而没有暴露其实现类的HelloServiceImpl

4.2. 导入Java
下面,我们将从HelloServiceBundle中导出的com.javaworld.sample.service包并将其导入到HelloWorldBundle中,具体步骤如下:
1). 请在com.javaworld.sample.HelloWorld Bundle中找到MANIFEST.MF文件,并在Manifest编辑器中打开,点击“Dependencies(依赖性)”标签,然后在“ImportPackage”里点击add按钮,在弹出的可用包的对话框,钩选“Show non-exported packages”,将com.javaworld.sample.service添加为导入包,这时,您的HelloWorldBundle中的MANIFEST.MF文件内容应如源代码清单6所示:
源代码清单6. HelloWorld Bundle中的MANIFEST.MF文件
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: HelloWorld Plug-in
Bundle-SymbolicName: com.javaworld.sample.HelloWorld
Bundle-Version: 1.0.0
Bundle-Activator: com.javaworld.sample.helloworld.Activator
Bundle-Vendor: JAVAWORLD
Bundle-Localization: plugin
Import-Package: com.javaworld.sample.service,
org.osgi.framework;version="1.3.0"

从上面的代码可以看出,Import-Package属性头的值是一个由逗号分隔的字符串,这是您想导入包的列表。在HelloWorldBundle示例代码中,我们引入了两个包,即com.javaworld.sample.serviceorg.osgi.framework
org.osgi.framework包中包含有OSGi框架类,比如,在HelloWorldBundle中的Activator.java中用到的BundleContextBundleActivator类都属于这个包。
2) 下面,请在Eclipse Java编辑器中打开com.javaworld.sample.helloworld.Activator.java,您会注意到,您现在可以访问HelloService接口,但不能访问HelloServiceImpl实现类,这是因为HelloServiceBunlde只导出了com.javaworld.sampel.service包,同时HelloWorldBundle也导入了这个包。HelloServiceImplHelloServiceBundle的一个内部类,任何其它的Bundle都不能访问它。
4.3. 类级别上的访问域
如果您运行示例的HelloService服务包,它会在Eclipse控制台上打印出”HelloWorld”。但是,如果您想在HelloWorld BundleActivator中访问HelloServiceImpl类,这时,编译没有问题,但在OSGi容器中运行这个Bundle时会抛出异常。
OSGi容器是如何能将jar文件中的一些类隐藏掉,而让另外一些类可见呢?这是因为OSGi容器使用Java类加载器来管理类的可见性,OSGi容器为每个Bundle创建不同的类加载器,因此每个Bundle能访问位于下列位置中的类:
a) 位于Java启动类路径下的、所有以Java.*开头的包中的类;
b) 位于OSGi框架类路径下的类,通常有一个独立的类加载器负责加载框架的实现类及关键的接口类;
c) 位于Bundle空间中的类,这些类通常包含在与Bundle相关的jar文件中,以及加到这个Bundle中的其它jar包中的类。
d) 导入包中的类,例如,HelloWorld Bundle导入了com.javaworld.sample.service包,因此它能访问该包中的类。Bundle级别的访问域是OSGi一个非常强大的功能,例如,它可以让您安全地更新HelloServiceImpl.java类,而不必担心依赖于这个类的代码受到破坏。
5. OSGi服务
前面我们提到,OSGi架构非常适合我们实现面向服务的应用(SOA)。它可以让Bundles导出服务,而其它的Bundles可以在不必了解源Bundles任何信息的情况下消费这些导出的服务。由于OSGi具有隐藏真实的服务实现类的能力,所有它为面向服务的应用提供了良好的类与接口的组合。
OSGi框架中,源BundleOSGi容器中注册POJO对象,该对象不必实现任何接口,也不用继承任何超类,但它可以注册在一个或多个接口下,并对外提供服务。目标Bundle可以向OSGi容器请求注册在某一接口下的服务,一旦它发现该服务,目标Bundle就会将该服务绑定到这个接口,并能调用该接口中的方法。下面我们举个例子,以便我们能更好理解与OSGi相关的这些概念。
5.1. 导出服务
在本小节中,我们将更新HelloService Bundle,以便它能把HelloServiceImpl类的对象导出为服务,具体步骤如下:
1) 修改com.javaworld.sample.HelloService Bundle中的MANIFEST.MF文件,让它导入org.osgi.framework包(译者注,这一步我们已经完成);
2) 新建Javacom.javaworld.sample.service.impl.HelloServiceActivator.java,其源代码如清单7所示;
源代码清单7. HelloServiceActivator.java

Java代码 复制代码 收藏代码
  1. public class HelloServiceActivator implements BundleActivator {   
  2. ServiceRegistration helloServiceRegistration;   
  3. public void start(BundleContext context)throws Exception {   
  4. HelloService helloService = new HelloServiceImpl();   
  5. helloServiceRegistration=context.registerService(HelloService.class.getName(), helloService, null);   
  6. }   
  7. public void stop(BundleContext context)throws Exception {   
  8. helloServiceRegistration.unregister();   
  9. }   
  10. }  
public class HelloServiceActivator implements BundleActivator {
ServiceRegistration helloServiceRegistration;
public void start(BundleContext context)throws Exception {
HelloService helloService = new HelloServiceImpl();
helloServiceRegistration=context.registerService(HelloService.class.getName(), helloService, null);
}
public void stop(BundleContext context)throws Exception {
helloServiceRegistration.unregister();
}
}

 
请注意,在源Bundle中,我们应使用BundleContext.registerService()方法导出服务,这个方法带三个参数:
a) 该方法第一个参数为您要注册的服务的接口名称。如果您想把您的服务注册到多个接口下,您需要新建一个String数组存放这些接口名,然后把这个数组作为第一个参数传给registerService()方法。在示例代码中,我们想把我们的服务导出到HelloServer接口名下;HelloService.class.getName()这个会打印出om.javaworld.sample.service.HelloService,即类的完整的名字。
b) 第二个参数是您要注册的服务的实际Java对象。在示例代码中,我们导出HelloServiceImpl类的对象,并将其作为服务;它是客服端请求服务名为第一个参数的服务时去直接调用的处理对象,也就是将这个参数内容作为服务返回给用户使用。
c) 第三个参数为服务的属性,它是一个Dictionary对象。如果多个Bundle导出服务的接口名相同,目标Bundle就可以使用这些属性对源Bundle进行过滤,找到它感兴趣的服务。
3) 最后,请修改HelloServiceBundle中的MANIFEST.MF文件,将Bundle-Activator属性头的值改为com.javaworld.sample.service.impl.HelloServiceActivator(这个是继承BundleActivator的类的完整路径,当你没写正确时,MANIFEST.MF文件会提示你找不到该BundleActivator,它是运行bundle的入口
现在HelloService Bundle就可以导出HelloServiceImpl对象了。当OSGi容器启动HelloServiceBundle时,它会将控制权交给HelloServiceActivator.java类,HelloServiceActivatorHelloServiceImpl对象注册为服务。下面,我们开始创建该服务的消费者。
5.2. 导入服务
在本小节中,我们将修改上面开发的HelloWorld Bundle,以便让它成为HelloService服务的消费者。您主要需要修改HelloWorldBundle中的Activator.java代码,修改后的代码如源代码清单8所示:
源代码清单8. HelloWorld Bundle中的Activator.java

Java代码 复制代码 收藏代码
  1. packagecom.javaworld.sample.helloworld;   
  2.   
  3. importorg.osgi.framework.BundleActivator;   
  4. importorg.osgi.framework.BundleContext;   
  5. importorg.osgi.framework.ServiceReference;   
  6. importcom.javaworld.sample.service.HelloService;   
  7.   
  8. publicclass Activator implements BundleActivator {   
  9. ServiceReference helloServiceReference;   
  10. public void start(BundleContext context)throws Exception {   
  11. System.out.println("HelloWorld!!");   
  12. helloServiceReference=context.getServiceReference(HelloService.class.getName());   
  13. HelloService helloService=(HelloService)context.getService(helloServiceReference);   
  14. System.out.println(helloService.sayHello());   
  15.   
  16. }   
  17. public void stop(BundleContext context)throws Exception {   
  18. System.out.println("Goodbye World!!");   
  19. context.ungetService(helloServiceReference);   
  20. }   
  21. }  
packagecom.javaworld.sample.helloworld;

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服务,该方法会返回排行最高的服务(服务的排行是通过Constants.SERVICE_RANKING属性指定的)。您一旦获得ServiceReference对象,您就可以调用其BundleContext.getService()方法获取真实的服务对象。
您可以参照运行Bundle的方法运行上面的示例应用,请点击“RunàRun…”菜单,并确保HelloWorldHelloService这两个Bundle被选中。当您启动HelloServiceBundle时,您会在控制台上看到“InsideHelloServiceImple.sayHello()”,这个消息是由HelloServiceImpl.sayHello()方法打印出来的。
5.3. 创建服务工厂
在上节中,我们学会了如何使用OSGi框架新建一个Java对象,并把它注册为一个服务,然后让其它的Bundle去消费这个服务。如果您看一下HelloServiceActivator.start()方法,您会注意到我们在start()方法中新建了HelloServiceImpl类对象,然后将它注册到HelloService接口名下。这样注册后,任何其它的Bundle在请求HelloService服务时,OSGi容器将返回同一对象。
在大多数情况下,这样的实现方法没有问题。但是,比如说我们要为每一个Bundle消费者返回不同的HelloServiceImpl对象,再比如说,您的服务对象要提供的服务为打开一个数据库连接,但并不是马上就打开它,而是在真正需要的时候才打开这个数据库连接。
对这两种情况,我们的解决方法是,新建一个类实现ServiceFactory接口,并把该类的对象注册为服务,但并不是注册实际的服务对象。一旦您完成这一步,其它Bundle在请求该服务时,您的ServiceFactory实现类将接管该请求,ServiceFactory会为每个Bundle新建一个服务对象,并将真实服务的创建时间延迟到有人真正需要该服务的时候。
下面我们将使用ServiceFactory更新我们上面开发的com.javaworld.sample.HelloServiceBundle,具体步骤如下:
1) 新建工厂 HelloServiceFactory.java,源代码如清单9所示。
源代码清单9 . HelloServiceFactory.java

Java代码 复制代码 收藏代码
  1. public class HelloServiceFactory implements ServiceFactory{   
  2.   
  3.     private int usageConter = 0 ;   
  4.        
  5.     //getService应该是客服端请求的HelloServiceFactory服务时自动调用的方法   
  6.     @Override  
  7.     public Object getService(Bundle bundle, ServiceRegistration serviceRegistration) {   
  8.         System.out.println("Create object of helloService for " + bundle.getSymbolicName());   
  9.         usageConter ++;   
  10.         System.out.println("Number of bundles using service " + usageConter);   
  11.         HelloService helloService = new HelloServiceImpl();   
  12.         return helloService;   
  13.     }   
  14.   
  15.     //ungetService应该是停止HelloServiceFactory服务时会调用到的方法   
  16.     @Override  
  17.     public void ungetService(Bundle bundle, ServiceRegistration serviceRegistration, Object object) {   
  18.         System.out.println("Release object HellowService for " + bundle.getSymbolicName());   
  19.         usageConter --;   
  20.         System.out.println("Number of bundles using service " + usageConter);   
  21.     }   
  22.   
  23. }  
public class HelloServiceFactory implements ServiceFactory{

	private int usageConter = 0 ;
	
	//getService应该是客服端请求的HelloServiceFactory服务时自动调用的方法
	@Override
	public Object getService(Bundle bundle, ServiceRegistration serviceRegistration) {
		System.out.println("Create object of helloService for " + bundle.getSymbolicName());
		usageConter ++;
		System.out.println("Number of bundles using service " + usageConter);
		HelloService helloService = new HelloServiceImpl();
		return helloService;
	}

	//ungetService应该是停止HelloServiceFactory服务时会调用到的方法
	@Override
	public void ungetService(Bundle bundle, ServiceRegistration serviceRegistration, Object object) {
		System.out.println("Release object HellowService for " + bundle.getSymbolicName());
		usageConter --;
		System.out.println("Number of bundles using service " + usageConter);
	}

}

  
从上面的代码中,我们可以看到,ServiceFactory接口定义了两个方法:
a) getService()方法:当某个Bundle第一次使用BundleContext.getService(ServiceReference)方法请求一个服务对象时,OSGi框架会调用该方法。在源代码清单9中,我们用这个方法为每个Bundle新建并返回不同的HelloServiceImpl对象,如果这个对象不是nullOSGi框架会缓存这个对象。如果同一个Bundle再次调用BundleContext.getService(ServiceReference)方法,OSGi将返回同一个服务对象。
b) ungetService()方法:当Bundle释放服务时,OSGi容器可以调用该方法销毁服务对象。在源代码清单9中,我们使用usageCounter变量来跟踪服务的使用数目,并打印出该服务的客户端数量。
2) 修改HelloService Bundle中的HelloServiceActivator.javastart()方法,让它注册到ServiceFactory接口名下,而不是注册到HelloService接口。详细代码如清单10所示:
源代码清单10. 修改后的HelloServiceBundle中的HelloServiceActivator.java

Java代码 复制代码 收藏代码
  1. package com.javaworld.sample.activator;   
  2.   
  3. import org.osgi.framework.BundleActivator;   
  4. import org.osgi.framework.BundleContext;   
  5. import org.osgi.framework.ServiceRegistration;   
  6.   
  7. import com.javaworld.sample.service.HelloService;   
  8. import com.javaworld.sample.service.impl.HelloServiceImpl;   
  9.   
  10. public class HelloServiceActivator implements BundleActivator{   
  11.   
  12.     ServiceRegistration helloServiceRegistration;    
  13.   
  14.     public void start(BundleContext context) throws Exception {   
  15.         /*//下面是使用同一个实例对象服务所的请求的方式:  
  16.         HelloService helloService = new HelloServiceImpl();  
  17.         helloServiceRegistration = context.registerService(HelloService.class.getName(), helloService, null);  
  18.         */  
  19.   
  20.         //下面是用工厂模式来向请求服务的用户提供不同的实例对象的方式   
  21.         HelloServiceFactory helloServiceFactory = new HelloServiceFactory();   
  22.         helloServiceRegistration = context.registerService(HelloService.class.getName(), helloServiceFactory, null);   
  23.     }   
  24.   
  25.     public void stop(BundleContext context) throws Exception {   
  26.         helloServiceRegistration.unregister();   
  27.     }   
  28. }  
package com.javaworld.sample.activator;

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

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

public class HelloServiceActivator implements BundleActivator{

	ServiceRegistration helloServiceRegistration; 

	public void start(BundleContext context) throws Exception {
		/*//下面是使用同一个实例对象服务所的请求的方式:
		HelloService helloService = new HelloServiceImpl();
		helloServiceRegistration = context.registerService(HelloService.class.getName(), helloService, null);
		*/

		//下面是用工厂模式来向请求服务的用户提供不同的实例对象的方式
		HelloServiceFactory helloServiceFactory = new HelloServiceFactory();
		helloServiceRegistration = context.registerService(HelloService.class.getName(), helloServiceFactory, null);
	}

	public void stop(BundleContext context) throws Exception {
		helloServiceRegistration.unregister();
	}
}

 

现在,您可以试运行示例代码。您会注意到,当HelloWorld Bundle启动时,服务计数器变为1;当HelloWorldBundle停止时,服务计数器的数目将变为0
5.4. 跟踪服务
在“OSGi服务”小节,您学会了如何使用服务的接口名搜索服务。但如果有多个Bundle使用同一接口名注册服务,那会发生什么呢?这时,OSGi容器将返回排行最高的服务,即,返回注册时那个SERVICE_RANKING属性值最大的服务。如果有多个服务的排行值相等,那么OSGi容器将返回PID值最小的那个服务。
但是,如果您的服务消费者需要了解某一接口下的服务对象何时注册、何时取消注册,这时,您应使用ServiceTracker类。下面,我们看看如何使用服务跟踪器来修改我们的示例代码,具体步骤如下。
1) 修改HelloWorldBundleMANIFEST.MF文件,让它导入org.osgi.util.tracker包;
2) 新建类HelloServiceTracker.java,其源代码参见清单11
源代码清单11.HelloServiceTracker.java

Java代码 复制代码 收藏代码
  1. public class HelloServiceTracker extends ServiceTracker {   
  2.   
  3.     public HelloServiceTracker(BundleContext context) {   
  4.   
  5.         super(context, HelloService.class.getName(),null);   
  6.   
  7.     }   
  8.   
  9.     public Object addingService(ServiceReference reference) {   
  10.   
  11.         System.out.println("Inside HelloServiceTracker.addingService " + reference.getBundle());   
  12.   
  13.         return super.addingService(reference);   
  14.   
  15.     }   
  16.   
  17.     public void removedService(ServiceReference reference, Object service) {   
  18.   
  19.         System.out.println("Inside HelloServiceTracker.removedService " + reference.getBundle());   
  20.   
  21.         super.removedService(reference, service);   
  22.   
  23.     }   
  24.   
  25. }  
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);

    }

}

 


在上面的HelloSerivceTracker类的构造函数中,您可以看到,我们把HelloService接口名传入其父类中,这相当于说,HelloServiceTracker应跟踪注册到HelloService接口名下的所有服务,HelloServiceTracker继承自ServiceTracker类,实现了下面两个方法:
a) addingService()方法:当Bundle使用接口名注册服务时,该方法将会被调用;
b)removedService()方法:当Bundle取消注册某个接口名下的服务时,该方法将会被调用。
3) HelloServiceTracker类更新我们的Activator.java类,以便让它来管理服务,而不是直接去查找它们,源代码请参见清单12
源代码清单12. 使用了HelloServiceTrackerActivator.java

Java代码 复制代码 收藏代码
  1. package com.javaworld.sample.helloworld;   
  2.   
  3. import org.osgi.framework.BundleActivator;   
  4. import org.osgi.framework.BundleContext;   
  5.   
  6. import com.javaworld.sample.service.HelloService;   
  7.   
  8. public class Activator implements BundleActivator {   
  9.   
  10. //  private ServiceReference helloServiceReference;   
  11.        
  12.     private HelloServiceTracker helloServiceTracker ;   
  13.        
  14.     public void start(BundleContext context) throws Exception {   
  15.         System.out.println("开启helloworld的bundle");   
  16.            
  17.         /*//下面是引用的方式来获取服务的  
  18.         helloServiceReference = context.getServiceReference(HelloService.class.getName());  
  19.         HelloService helloService = (HelloService)context.getService(helloServiceReference);  
  20.         */  
  21.            
  22.         //下面是将请求的服务交给serviceTracker来管理,那么就可以在开启和关闭时足跟踪到服务的状态情况。   
  23.         helloServiceTracker = new HelloServiceTracker(context);   
  24.         helloServiceTracker.open();   
  25.         HelloService helloService = (HelloService)helloServiceTracker.getService();   
  26.            
  27.         System.out.println("开始调用远程helloService的sayHello方法:");   
  28.         System.out.println(helloService.sayHello());   
  29.         System.out.println("远程调用完成!");   
  30.     }   
  31.   
  32.     public void stop(BundleContext context) throws Exception {   
  33.         System.out.println("Goodby world!");   
  34. //      context.ungetService(helloServiceReference);   
  35.            
  36.         helloServiceTracker.close();   
  37.     }   
  38. }  
package com.javaworld.sample.helloworld;

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

import com.javaworld.sample.service.HelloService;

public class Activator implements BundleActivator {

//	private ServiceReference helloServiceReference;
	
	private HelloServiceTracker helloServiceTracker ;
	
	public void start(BundleContext context) throws Exception {
		System.out.println("开启helloworld的bundle");
		
		/*//下面是引用的方式来获取服务的
		helloServiceReference = context.getServiceReference(HelloService.class.getName());
		HelloService helloService = (HelloService)context.getService(helloServiceReference);
		*/
		
		//下面是将请求的服务交给serviceTracker来管理,那么就可以在开启和关闭时足跟踪到服务的状态情况。
		helloServiceTracker = new HelloServiceTracker(context);
		helloServiceTracker.open();
		HelloService helloService = (HelloService)helloServiceTracker.getService();
		
		System.out.println("开始调用远程helloService的sayHello方法:");
		System.out.println(helloService.sayHello());
		System.out.println("远程调用完成!");
	}

	public void stop(BundleContext context) throws Exception {
		System.out.println("Goodby world!");
//		context.ungetService(helloServiceReference);
		
		helloServiceTracker.close();
	}
}

 

我们看到,在初始的start()方法中,我们首先新建一个HelloServiceTracker对象,然后要求这个对象跟踪HelloService接口下的服务。这时,我们可以调用getService()方法获得HelloService对象。
如果您试运行上面的示例代码,您会注意到,在启动或停止HelloSerivceBundle时,OSGi容器都会调用HelloServiceTracker对象的addingService()方法或removedService()方法。

 

当我们在一个bundle里作了修改时,我们可以通过update的命令将最新的bundle更新上来,这样我们就可以不用重新运行,而是直接可以看到更新的效果。这个就是OSGI的热安装的最显著特征。


 

这里补充一下运行的方式:

打开Run configurations,在OSGI Framework里新建一个运行平台,并将它名字改为你想起的名,选择我们写好的bundles(如果有引用它其它bunble,如spring依赖bundles,那也要选中),然后点击Add Required Bundles,就可以添加入有依赖其它bundles而没有引入的bundle,最后点击Validate Bundles来最后确认依赖包加全了没有,提示No problems were dected.便可以运行了。

 结论

这是“你好,
OSGi”系列三篇文章的第一篇,我向您介绍了使用OSGi进行模块化应用开发的一些基本概念。您现在已了解到,当前有三种开源的OSGi容器,而且您还练习了如何使用Eclipse自带的OSGi容器Equinox开发一个简单的Bundle;同时,您也学会了Bundle之间是怎样通过导出导入彼此的包和服务,从而达到彼此交互的目的。
在本文中,您也许注意到,开发OSGi Bundle的一个挑战是,您的每个Bundle都需要了解OSGi API,在某些开发场景中,这可能意味着我们要许多基础代码。在本系列的下一篇文章中,我将向您介绍“SpringDynamic Modules for OSGi Service Platforms(OSG服务平台的Spring动态模块,亦称为SpringOSGi)”项目,该项目将会简化OSGi Bundle 的开发。另外,您也可以参考本文的资源部分,学习更多关于OSGi的知识。

7.
作者介绍

Sunil Patil是一位Java企业/门户开发者,现就职于加州三藩市的AscendentTechnology公司。他是Java Portlets 101一书的作者(该书由SourceBeat公司20074月出版),而且,他还写了许多文章,通过O’ReillyMedia发表。Sunil曾经在IBMWebspherePortal Server开发团队工作过3年。现在,他积极参与Pluto社区。另外,他拥有IBM WebspherePortal Server 5.05.1版本的开发者证书,Sun SCJP证书和Web组件开发者证书,同时,他还是商务组件的开发者。您可以访问Sunil的博客:http://jroller.com/page/SunilPatil

8.
资源

非官方的
OSGi规范开始于1999年,最近,JSRJava模块化支持分为两个规范,即,JSR 277(Java模块系统,http://jcp.org/en/jsr/detail?id=277 )JSR 291(Java动态组件支持,http://jcp.org/en/jsr/detail?id=291 )。在这两个JSR规范中,人们对哪个规范应该包含在Java EE6中,有过很多争议,请参考http://www.infoq.com/news/2007/08/osgi-jsr277-debate
和许多Java开发者一样,SebastienArbogast最近意识到OSGi的重要性(请参见http://osgi.dzone.com/news/why-osgi-zone ),他在Javalobby上开辟了OSGi专区(请参见http://osgi.dzone.com/ ),作为OSGi相关信息和讨论的平台。
如果您想了解
OSGi服务规范第4版的信息,请参考http://www2.osgi.org/Release4/HomePage;关于OSGi服务规范第4版的Java API,请参考http://www2.osgi.org/javadoc/r4/;关于OSG服务平台的Spring动态模块项目,有时也称作Spring OSGi项目,请参考http://www.springframework.org/osgi


本文译自http://www.javaworld.com/javaworld/jw-03-2008/jw-03-osgi1.html      

分享到:
评论

相关推荐

    交互修改.rp

    交互修改

    14230-2.pdf

    ISO14230-2标准文档,定义了K线通讯方式和数据格式,对于汽车诊断非常有用

    基于python的求职招聘网站 python+django+vue搭建的求职招聘管理系统 - 毕业设计 - 课程设计.zip

    学习作者过程中,遇到问题可以咨询解决方案前台地址http://job.gitapp.cn后台地址http://job.gitapp.cn/admin后台管理帐号用户名admin123 密码admin123功能介绍平台采用B/S结构,前端采用主流的Python语言进行开发,前端采用主流的V​​ue.js进行开发。整个平台包括前台和后台两个部分。前台功能包括首页、岗位详情页、简历中心、用户设置模块。后台功能包括总览、岗位管理、公司管理、分类管理、标签管理、评论管理、用户管理、运营管理、日志管理、系统信息模块。代码结构服务器目录编号web目录是前端代码部署运行执行步骤(1)安装python 3.8(2) 安装依赖。进入server目录下,执行 pip install -r requests.txt(3)安装mysql 5.7数据库,并创建数据库,创建SQL如下CREATE DATABASE IF NOT EXISTS xxx DEFAULT CHARSET utf8 COLLATE utf8_general_ci(4)恢复

    4602-职业规划设计书PPT护理.pptx

    4602-职业规划设计书PPT护理

    非常好的SqlServer查询性能优化教程资料100%好用.zip

    非常好的SqlServer查询性能优化教程资料100%好用.zip

    基于Springboot+Vue+Python深度神经网络学习算法水质管理预测系统设计毕业源码案例设计.zip

    基于Springboot+Vue+Python深度神经网络学习算法水质管理预测系统设计毕业源码案例设计Springboot_Vue_Python_水质管理_预测基于Springboot+Vue+Python深度神经网络学习算法水质管理预测系统设计毕业源码案例设计程序开发软件Eclipse/Idea + WebStorm/VsCode + Pycharm 数据库mysql 开发技术Springboot + Vue + Python 这个是一个水质管理和预报系统,它是一个全栈Web应用程序,使用机器学习和深度神经网络算法来预测未来的水质。系统一共有2个身份包括管理员和用户。管理员登录后可以查询最新水质检测数据,也可以上报新的水质数据,可以查询管理历史水质数据,查询历史水质趋势图,训练自己的模型参数,选择一个算法模型结果预测下个月的水质信息,管理所有的用户信息用户登录后比管理员就少了个用户管理功能。管理员账号密码 admin/123 用户账号密码user1/123

    微信小程序云开发毕业设计「单词天天斗」,好友,匹配,人机对战,单词本科毕设打字稿原创微信小程序.zip

    单词天天斗 (毕业设计/实战小程序/微信小程序完整项目)介绍该项目基于「微信小程序」原生框架和「微信小程序云开发」实现单词对战类小程序,支持好友对战、随机匹配、人机对战透明不同模式的「对战模式」另外提供「每日对战」词汇」、「生词本」、「排行榜」、「设置」等功能,实现完整的业务闭环。单词库包含从小学、初中、高中、四六级、考研、雅思等常需掌握的词汇,支持自定义词库,支持自定义拓展无限本单词书。技术栈主要为微信小程序、云开发、TypeScript等,从头搭建项目,基于git管理代码版本,使用eslint作为代码格式校验,并对页面进行组件化拆分,前端和云函数均采用TypeScript。实践小程序能力,如用户信息获取、用户登录、全局状态管理、路由、wxs、npm包、播放音频、回复、转发分享、动画、云数据库等。项目提供完整设计稿,项目演示可查看微信小程序「单词天天斗」,扫码体验 ↓这些人毕设参考项目文档齐全、题目合适、技术广度大、业务闭环,包含项目解析文档和教程,这是一个非常适合作为毕设学习的小程序项目。无化部署运营无论你是想通过小程序现变,还是想给自己的「英语课程教材」

    利用ReST与ReAct自改进多步骤推理的大规模语言模型代理

    内容概要:本文提出了结合强化自我训练(ReST)和响应动作链路(ReAct)的方法来构建并改善大规模语言模型代理的性能,尤其是在需要多步骤推理以解决复杂自然语言查询的任务上。文中定义了一个能够在外部工具/ API /环境交互中表现出色的代理,并提出了一种通过迭代训练以前的轨迹来进行连续自我提升和精炼的技术路径。 适合人群:对大型语言模型研究及应用有兴趣的研究人员和工程师。 使用场景及目标:本方法主要适用于处理需要多个信息检索步骤才能完成的问题解决任务,如基于复杂开放性问答系统的发展。具体目标是在减少所需参数量的前提下提高此类系统的准确性、鲁棒性和效率。 其他说明:作者展示了仅经过两轮迭代优化,即可以从一个大的预训练模型蒸馏出性能相当但大小减少两个数量级的小型化模型。此外,在整个过程中没有使用人类标记的数据进行直接监督。

    毕业设计Android,一款水果健康百科app.zip

    毕业设计Android,一款水果健康百科app斯戈利毕业设计Android,一款水果健康百科app

    移动互联网发展和岗位分析.pptx

    移动互联网发展和岗位分析.pptx

    数控加工程序设计.pptx

    数控加工程序设计.pptx

    毕业设计基于STM32的智能停车场设计.zip

    毕业设计基于STM32的智能停车场设计基于STM32的智能停车场设计项目介绍该项目为毕业设计。基于STM32F1平台的智能停车场,板卡划分为主板、控制台指示板及场内红外检测板,支持短信定时报告停车场状态与远程控制、进出场自动电梯停车杆并播报欢迎消息、检测车位和环境温湿度并在屏幕实时显示状态。目前阶段正在进行电路验证设计与打样阶段。预计2月上旬至中旬完成电路设计并进入编码阶段。目前功能概述车辆进场与退场时,语音播报相应的欢迎语句并自动升起停车杆。待车辆完全驶入停车场后,自动降下停车杆。通过红外方式检测车位停车状态,并在门口控制台和相应车位显示停车状态。屏幕显示当前可用车票和当前温湿度每1小时通过短信报告目前停车场车位情况、1小时内车辆进出数量。短信下发控制指令。后续阶段功能车辆停车计费功能。冲卡检测并自动报警功能。加入实时时钟,通过短信安排时间。用户使用场景功能列表模块 功能 商品分类STM32F103VET6 微型系统板 毕业设计使用的开发板 单片机F103VESIM800L模块 支持GPRS短信收发的功能 12864液晶屏

    基于SpringBoot+Vue.js的轻小说在线阅读网站前后端分离全部资料+详细文档.zip

    【资源说明】 基于SpringBoot+Vue.js的轻小说在线阅读网站前后端分离全部资料+详细文档.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    “腾达”游戏分享网站的设计与实现_97c7a2s2.zip

    “腾达”游戏分享网站的设计与实现_97c7a2s2

    大数据与会计 (9).docx

    大数据与会计 (9)

    数学建模matlabppt课件市公开课一等奖百校联赛特等奖课件.pptx

    数学建模matlabppt课件市公开课一等奖百校联赛特等奖课件.pptx

    城市轨道交通通信信号技术_.docx

    城市轨道交通通信信号技术_

    【毕业设计+开题答辩】-基于JAVA_JSP电子书下载系统-【源代码+截图+数据库+论文+视频讲解】

    本文中的项目资源均整理自互联网,若侵犯了您的权益,请及时联系博主,博主会及时处理。 项目资源中使用的技术和系统用处不一定准确和全面,我只是大致的浏览了一下,具体使用技术建议参考代码和视频讲解。 资源中的各内容不一定每一个都非常的完美,可能会有少许错误,建议多看几个,选其中一个自己觉得不错的,用来做毕设或者开题等等。 资源中所列论文可以参考,但是不建议且强烈不建议直接照搬照抄,因为毕竟要查重,避免引起不必要的麻烦。

    压力表计算机软件及应用it计算机专业资料.pptx

    压力表计算机软件及应用it计算机专业资料.pptx

    钢材器材破损铁锈检测69-YOLO(v5至v9)、COCO、CreateML、Darknet、Paligemma、TFRecord、VOC数据集合集.rar

    钢材器材破损铁锈检测69-YOLO(v5至v9)、COCO、CreateML、Darknet、Paligemma、TFRecord、VOC数据集合集.rar钢重用-V4 2024-03-27 5:01 PM ============================= *与您的团队在计算机视觉项目上合作 *收集和组织图像 *了解和搜索非结构化图像数据 *注释,创建数据集 *导出,训练和部署计算机视觉模型 *使用主动学习随着时间的推移改善数据集 对于最先进的计算机视觉培训笔记本,您可以与此数据集一起使用 该数据集包括1094张图像。 钢元素以可可格式注释。 将以下预处理应用于每个图像: *像素数据的自动取向(带有Exif-Arientation剥离) *调整大小为416x416(拉伸) 应用以下扩展来创建每个源图像的3个版本: *水平翻转的50%概率 *以下90度旋转之一的同等概率:无,顺时针,逆时针方向 * -15%至+15%之间的随机BRIGTHNESS调整 * 0到0.8像素之间的随机高斯模糊

Global site tag (gtag.js) - Google Analytics