Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从静态方法解析OSGi服务实例_Java_Spring_Osgi_Jndi - Fatal编程技术网

Java 从静态方法解析OSGi服务实例

Java 从静态方法解析OSGi服务实例,java,spring,osgi,jndi,Java,Spring,Osgi,Jndi,我有一个遗留的Java企业应用程序,它将一组服务注册为Springbean并向JNDI注册。我想将其转换为使用Spring和OSGi 以前,服务类只是包含在任何其他需要它的类的类路径中,并且有一个静态方法,如下所示: public class SomeService { // private fields... public static SomeService getInstance() { SomeService svc = null; tr

我有一个遗留的Java企业应用程序,它将一组服务注册为Springbean并向JNDI注册。我想将其转换为使用Spring和OSGi

以前,服务类只是包含在任何其他需要它的类的类路径中,并且有一个静态方法,如下所示:

public class SomeService {
    // private fields...

    public static SomeService getInstance() {
        SomeService svc = null;
        try {
            InitialContext ctx = new InitialContext();
            svc = (SomeService)ctx.lookup("java:/SomeService");
        } catch (NamingException ex) {
            logger.info("Exception in getNamedObject", ex);
        }
        return svc;
    }

    // Setters and getters, some of which are filled-in with Spring beans

    // Other methods etc...
}
SomeService svc = SomeService.getInstance();
// or even
SomeObject results = SomeService.getInstance().getSomeObject();
无论使用哪种服务,我们都有如下代码:

public class SomeService {
    // private fields...

    public static SomeService getInstance() {
        SomeService svc = null;
        try {
            InitialContext ctx = new InitialContext();
            svc = (SomeService)ctx.lookup("java:/SomeService");
        } catch (NamingException ex) {
            logger.info("Exception in getNamedObject", ex);
        }
        return svc;
    }

    // Setters and getters, some of which are filled-in with Spring beans

    // Other methods etc...
}
SomeService svc = SomeService.getInstance();
// or even
SomeObject results = SomeService.getInstance().getSomeObject();
现在,我意识到转换这个的“正确”方法是完全删除
getInstance()
,并强制接口的所有用户拥有自己对实现的引用,该实现由Spring提供,并在META-INF的xml文件中配置。但是,这个更改太大,无法一次完成,因为系统已经在生产中)

有没有类似于上述JNDI方法的方法来获取OSGi服务的实例

更新:一些澄清
我要特别明确我的目标——我知道这通常不是一个好方法。然而,这是一个正在生产中的大型企业应用程序,一次性改变整个过程以适应“理想”的OSGi结构实在是太大了,不可能一次完成所有的改变

我在这里试图完成的是将应用程序的一小部分分离出来,并将其作为单独的OSGi包提供。但是,由于应用程序的其余部分(如果您愿意的话,“客户机代码”)尚未准备好进行此更改,因此我必须有一个中间步骤,让我能够以旧的方式使用此代码,并将其作为OSGi服务使用。随着时间的推移,应用程序的其余部分也将被模块化和OSGi化,最终这些静态工厂方法将被完全删除


然而,在那之前,“这是做OSGi的错误方式”的评论对我没有多大帮助-我知道没有,但这甚至不是我的最终形式…

你在试图将方形销钉推过一个圆孔。在计算机科学101中,每个开发人员都知道全局变量是不好的,所以我想说,关于“correct”的引用是非常错误的,因为静态变量是主要的全局变量

因为OSGi从不依赖全局变量(java中的静态),所以您可以在OSGi之上运行的应用服务器上的WAR文件中,在OSGi中的OSGi中运行OSGi。静态是邪恶的(首先由OSGi的前身ServiceSpace的作者Anselm Baird说)。开发服务模型是为了解决您遇到的问题;任何服务实现都可以通过其接口和/或属性从任何位置引用另一个服务:

 @Reference
 void setSomeService(SomeService s) {
     this.s = s;
     ...
 }
在模块化系统中,一个中心神XML是一种诅咒

您的问题没有解决方案,因为您将不可避免地遇到订购问题。在OSGi中,服务不一定可用(它最强大、最容易被误解的特性之一)。您的服务提供商可以随时自由进出。因为您的静态模型不处理依赖关系,所以它将错误地失败,因为它假定隐式排序。现在很多人做这些静态的解决方案,因为它往往在大多数时间工作;然而,我认为“大部分时间”对计算机软件来说还不够好。如果我们要对我们的产品负责,不要认为我们会这么做

假设您使用Eclipse或其他IDE进行重构,那么我很难理解为什么很难更改代码库来注入此服务


OSGi不像大多数Java库那样是一种临时的饮食,也不是一种神奇的调味品,它是一种成熟的模块化系统,要求您的应用程序真正模块化,也就是说,它是一种生活方式的改变。在我的经验中,试图使用一个框架,但又违背了它的流程,这是一种策略,会导致很多悲伤。

我想我已经找到了一种方法来做到这一点——我正在努力测试它,但从文档来看,这种方法似乎很有希望

我创建了一个解析器类,它负责实际从OSGi获取服务,并通过实现
BundleContextAware
来实现。这样,我希望注入一个
BundleContext
,我可以从中获取一个服务实例:

public class SomeServiceResolver implements BundleContextAware {
    private BundleContext _cxt;

    @Override
    public void setBundleContext(BundleContext context) {
        _cxt = context;
    }

    public SomeService resolveService() {
        // TODO: Add error handling if service isn't available
        ServiceReference<SomeService> svcref = _ctx.getServiceReference(SomeService.class);
        SomeService svc = _ctx.getService(svcref);
        return svc;
    }
}

正如我所说,我还没有测试过它,所以我们将看看它是否真的有效。

在任何情况下,您都希望将您的服务发布为OSGi服务。问题只是如何在对客户端代码影响最小的情况下访问它

一种方法可能是使用:

FrameworkUtil.getBundle(YourClass.getBundleContext(); 这允许在静态方法中访问bundle上下文。从那里您可以访问该服务

另一个办法是使用。它允许您使用jndi检索OSGi服务。因此,这也应该有所帮助


当然,正如Peter所说,这应该只是一个临时解决方案。

我必须克服一个类似的问题,即一个发布的静态接口,它提供用户使用的服务,所以我不能强迫他们完全使用OSGI。以下带注释的代码对我来说效果很好,所以也许其他人也能从中受益

@Component(immediate=true, service=ServiceProvider.class, scope=ServiceScope.SINGLETON)
public class ServiceProvider {

    private static FooService fooService;

    @Reference(cardinality=ReferenceCardinality.MANDATORY)
    public void setFooService(FooService fooService) {
        ServiceProvider.fooService = fooService;
    }

    /**
     * This is the existing Method which should return
     * a FooService Object.
     * @return The 'static' FooService
     */
    public static FooService getFooService() {
        return fooService;
    }
}
在启用插件开发->DS Annotations for 1.3的Eclipse(4.8光子)中,这将生成文件

OSGI-INF/your.package.name.ServiceProvider.xml
包含以下OSGI服务声明

<scr:component ...>
    <service scope="singleton">
        <provide interface="your.package.name.ServiceProvider"/>
    </service>
    <reference bind="setFooService" cardinality="1..1" interface="foo.service.package.FooService" name="FooService"/>
    <implementation class="your.package.name.ServiceProvider"/>
</scr:component>
在运行时

setFooService(...)
方法,并按预期注入FooService对象,因此对

ServiceProvider.getFooService();

也将像以前一样工作。

最终我们将迁移所有代码以注入服务,但目前这不是一个选项-不是因为很难重新编写代码,而是因为不可能在可扩展的未来将代码部署到生产中,因为这样做需要重新启动不能随意关闭的系统。如果我能找到一个中间解决方案,将服务导出为osgi服务,同时仍然允许旧的访问方式,那么我们可以重新编写系统的这一部分,部署服务包,并在oth中进行更改