激活后OSGI声明性服务注入

时间:2015-11-16 14:25:42

标签: java osgi

我们如何确保在activate()调用之前注入所有依赖项?

    private IMyDependency aInstance, bInstance, cInstance;

    public void setDependency(IMyDependency depInstance) {

        Bundle depBundle = FrameworkUtil.getBundle(depInstance.getClass());

        logger.debug("Dependency {} from bundle {} retrieved", depInstance, depBundle.getSymbolicName());

        if (A_BUNDLE_NAME.equals(depBundle.getSymbolicName())) {
            aInstance = depInstance;
        } else if (B_BUNDLE_NAME.equals(depBundle.getSymbolicName())) {
            bInstance = depInstance;
        } else if (C_BUNDLE_NAME.equals(depBundle.getSymbolicName())) {
            cInstance = depInstance;
        } else {
            logger.error("Dependency {} from unknown bundle {}", depInstance, depBundle);
        }
    }

    public void activate() {
        Preconditions.checkNotNull(aInstance);
        Preconditions.checkNotNull(bInstance);
        Preconditions.checkNotNull(cInstance);
        //...
    }

有多个IMyDependency实例,依赖基数为0..n

问题是,setDependency()有时在activate()方法之后调用。解决方法是更改​​依赖包的启动级别,但我们真的不想触摸配置。

4 个答案:

答案 0 :(得分:2)

现在对于带有注释的整个组件:

 @Component public class MyComponent {

   @Reference(target="(dependencyType=A)") IMyDependency aInstance;
   @Reference(target="(dependencyType=B)") IMyDependency bInstance;
   @Reference(target="(dependencyType=C)") IMyDependency cInstance;


   @Activate public void activate() {
    // all guaranteed set
   }
}

实例组件:

@Component public class MyDependency implements IMyDependency {
   ...
}

您应该使用configuration创建3个实例。

答案 1 :(得分:1)

通过Balazs'评论,我能够将0..n个依赖项更改为3个显式1..1个依赖项:

<reference bind="setDependencyA" cardinality="1..1" interface="com.example.IMyDependency" name="DepA" policy="static" target="(dependencyType=A)"/>
<reference bind="setDependencyB" cardinality="1..1" interface="com.example.IMyDependency" name="DepB" policy="static" target="(dependencyType=B)"/>
<reference bind="setDependencyC" cardinality="1..1" interface="com.example.IMyDependency" name="DepC" policy="static" target="(dependencyType=C)"/>

依赖类:

    public void setDependencyA(IMyDependency depInstance) {
        aInstance = depInstance;
    }

    public void setDependencyB(IMyDependency depInstance) {
        bInstance = depInstance;
    }

    public void setDependencyC(IMyDependency depInstance) {
        cInstance = depInstance;
    }

我还必须更改依赖项的激活(不幸的是,依赖项不使用DS):

@Override
public void start(BundleContext context) throws Exception {
    Hashtable<String, String> props = new Hashtable<>();
    props.put("dependencyType", "A");
    srvReg = context.registerService(IMyDependency.class.getName(), myInstance, props);
}

答案 2 :(得分:1)

我想你想要的是一种插件系统。所以你知道界面,但是你不知道有多少个impls,但是你想确保在加载之前加载所有的impls。

在OSGi中这并不容易。事实上,额外的服务可能会在运行时出现。因此,一种解决方案是简单地适应服务的所有变化。在某些情况下,这还不够。

例如,我有一个案例,我想为我的应用程序提供安全插件。我的软件包在没有安全插件的情况下启动是不可接受的,但它应该是可配置的。

所以我做的是使用OSGi属性为每个插件命名,在插件机制中我允许列出要在配置pid中加载的所有插件的名称。该机制确保主应用程序仅在所有命名插件都存在时启动。不幸的是,这种机制并没有内置到DS中,但您可以使用bind和unbind方法实现它。

答案 3 :(得分:0)

普通的OSGi在管理依赖关系方面非常坚定。你应该明确你的依赖链。通过实施智能服务跟踪器可以延长初始化时间,直到所有依赖项都可用为止,您可以获得更多动态。但是,我建议您使用声明性服务来避免旧式依赖注入。