基于OSGi的企业级开发框架实践——OSGi Annotations

我们的开发框架之所以选择使用Spring框架,是因为它提供了一个简单易用的Bean编程模型(采用IoC和AOP设计模式),通过XML配置文件简化了复杂而冗长的Bean初始化以及依赖关系的定义。不过随着Bean数量的不断增加,XML配置文件也将随之失去控制,我们很容易的就陷入了XML配置漩涡。自从Spring2.5版本推出之后,通过Annotation的方式,大大减少了XML的配置工作量。但是在Spring的OSGi版本中(Spring DM),XML的配置工作量依然可观,我们仍旧在使用<osgi:service/>和<osgi:reference/>元素来定义OSGi服务的注册和引用,由于OSGi服务的增加,我们很容易会去引用一个尚未注册的OSGi服务,一旦引用了一个未注册的OSGi服务则整个应用程序将无法正确运行。之前我还专门写过一篇文章《在Spring DM中使用Annotations发布和引用服务》,大致介绍了在Spring DM中如何使用Annotation来简化OSGi的使用,有兴趣的同学可以先去阅读一下这篇文章。接下去我们通过一个具体的实例来说明如何使用OSGi Annotation。

在Bundle中要使用OSGi Annotation,首先要定义两个BeanPostProcessor。在上一篇文章中我们已经提及过,这里我们深入的介绍它,如下图所示:

基于OSGi的企业级开发框架实践——OSGi Annotations_第1张图片

(图一)

以上两个Bean均继承至org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter,目的是为了在Spring实例化每个Bean时可以执行附加的操作,在这里我们就是要拦截初始化之后的Bean对象,检查它是否存在OSGi的Annotation,如果存在,则将此Bean注册为一个OSGi服务并登记到OSGi容器中。如果是需要引用一个OSGi服务,则会查找OSGi容器中所对应的服务,然后将其注入到当前的Bean中。其实工作原理还是比较简单易懂的。不过要记住,为了在某个Bundle中使用OSGi Annotation,必须要在当前Bundle的Spring XML中定义这两个后置处理Bean。

我们先在biz-share Bundle中编写一个接口:

package org.storevm.helloworld.biz.share;

/**
 * 
 * @author Administrator
 * @version $Id: OsgiServiceTest.java, v 0.1 2013-2-27 下午12:49:00 Administrator Exp $
 */
public interface OsgiServiceTest {
    /**
     * 输出
     */
    void out();
}

然后编写一个实现类:

package org.storevm.helloworld.biz.share.impl;

import org.apache.log4j.Logger;
import org.storevm.eosgi.core.annotation.OsgiService;
import org.storevm.eosgi.core.utils.LogUtils;

/**
 * 
 * @author Administrator
 * @version $Id: OsgiServiceTestImpl.java, v 0.1 2013-2-27 下午12:53:24 Administrator Exp $
 */
@Component
@OsgiService(interfaces = { OsgiServiceTest.class })
public class OsgiServiceTestImpl implements OsgiServiceTest {
    private static final Logger LOGGER = Logger.getLogger(OsgiServiceTest.class);

    /** 
     * @see org.storevm.helloworld.biz.share.OsgiServiceTest#out()
     */
    @Override
    public void out() {
        LogUtils.info(LOGGER, "这是一个OSGi服务, name={0}", OsgiServiceTest.class);
    }

}

注意在类的起始处,我们定义了如下的Annotation:

@Component
@OsgiService(interfaces = { OsgiServiceTest.class })

第一个Annotation是将OsgiServiceTestImpl注册到Spring的上下文容器中,由容器来管理它的生命周期。第二个Annotation是将OsgiServiceTestImpl注册为一个OSGi服务,注意,在注册OSGi服务时需要提供接口类型。至此我们的OSGi服务就算发布完成了,我们不再需要<osgi:service />配置元素,也不需要在XML中注册该Bean,所有的配置均通过Annotation完成。在Eclipse IDE中启动OSGi运行时容器,我们可以看到在Console中显示的如下日志信息:

基于OSGi的企业级开发框架实践——OSGi Annotations_第2张图片

(图二)

我们可以看到,OsgiServiceTest已经被成功发布为一个OSGi服务了。不过问题还没有结束,我们只是发布了一个OSGi服务,但是其他的Bundle还不知道这个OSGi服务的存在,因此为了让其他Bundle可以使用这个服务,我们还必须将服务暴露出去,请打开biz-share Bundle中的MANIFEST.MF文件,并切换到“Runtime”选项卡。如下图所示:

基于OSGi的企业级开发框架实践——OSGi Annotations_第3张图片

(图三)

开发框架已经将所有在org.storevm.helloworld.biz.share包中的服务暴露出去了。当然,如果你需要暴露其他包中的服务,可以点击“Add”按钮,在弹出的“Exported Packages”对话框中选择需要导出的Package,然后点击“OK”按钮即可,如下图所示:

基于OSGi的企业级开发框架实践——OSGi Annotations_第4张图片

(图四)

注意:一般情况下,我们只会将接口暴露给其他Bundle引用,而不会把具体的实现类暴露出去。

接下去我们在biz-service-impl Bundle中引入biz-share Bundle发布的OSGi服务。请打开biz-service-impl Bundle中的MANIFEST.MF文件并切换到Dependencies选项卡下,如下图所示:

基于OSGi的企业级开发框架实践——OSGi Annotations_第5张图片

(图五)

从上图中我们可以发现,biz-share Bundle已经被开发框架默认配置成Required Bundle了,所以我们无需再引入该Bundle,请关闭MANIFEST.MF文件。

接下来我们在biz-service-impl Bundle中编写一个调用OSGi服务的测试类,如下所示:

package org.storevm.helloworld.biz.service.impl;

import org.storevm.eosgi.core.annotation.ServiceReference;
import org.storevm.helloworld.biz.share.OsgiServiceTest;

/**
 * 
 * @author Administrator
 * @version $Id: InvokeOsgiServiceTest.java, v 0.1 2013-2-27 下午1:22:45 Administrator Exp $
 */
@Component
public class InvokeOsgiServiceTest {
    /* OSGi服务 */
    private OsgiServiceTest osgiServiceTest;

    /**
     * 调用服务
     */
    @PostConstruct
    public void invoke() {
        osgiServiceTest.out(); //调用OSGi服务
    }

    /**
     * Setter method for property <tt>osgiServiceTest</tt>.
     * 
     * @param osgiServiceTest value to be assigned to property osgiServiceTest
     */
    @ServiceReference
    public void setOsgiServiceTest(OsgiServiceTest osgiServiceTest) {
        this.osgiServiceTest = osgiServiceTest;
    }

}

这里的关注点是OsgiServiceTest Bean的注入,我们可以看到在Setter方法处使用了如下的Annotation:

@ServiceReference

通过该Annotation,当前Bean在实例化之后会去查找OSGi容器中是否有注册为osgiServiceTest的服务,如果有就会将该服务的引用对象注入到当前Bean中,如果没有就会抛出异常。

好了,让我们重新启动Eclipse IDE中的OSGi运行时容器,如果之前已经启动了,则在Console中输入close命令来关闭OSGi容器,然后再启动它。我们在启动日志中会看到如下内容:

基于OSGi的企业级开发框架实践——OSGi Annotations_第6张图片

(图七)

从上图中可以看到,我们的OSGi服务调用成功了。

在下一章中,我们将涉足分布式OSGi领域,看看开发框架为我们提供了怎么样的工具来帮助我们发布分布式的OSGi服务。

你可能感兴趣的:(基于OSGi的企业级开发框架实践——OSGi Annotations)