我想将我的EE应用程序迁移到OSGi。我的应用程序包括业务库,数据库JPA / Entities和REST / WS接口。它还有一个网络客户端。
我首先对结构进行原型设计,并使所有接口和捆绑包以OSGi方式相互通信。我希望在没有任何特定供应商或框架的情况下尽可能使用干净的规范。
我正在使用bnd maven插件来生成清单和声明性服务。我希望使用注入从我的其余资源调用OSGI服务(在另一个包上):
@Path("some-resources")
@Component
public class SomeResources{
private SomeService service = null;
@Reference
public void setController(SomeService service) { // <- this is never called
this.service = service;
}
@GET
@Produces(javax.ws.rs.core.MediaType.APPLICATION_XML)
public Object getSomeService() { // <- called
try {
service.process("Hello World"); // <- Error null object
}
...
}
我可以使用bnd @Component
注释资源,是否可以注入@Resource
?
一切正常,但服务始终为空。
为BND声明我的捆绑包以使其成为web / wab包的方式应该是什么?
我使用maven bundle:
<packaging>bundle</packaging>
...
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<dependencies>
<dependency>
<groupId>biz.aQute</groupId>
<artifactId>bndlib</artifactId>
<version>1.50.0</version>
</dependency>
</dependencies>
<configuration>
<supportedProjectTypes>
<supportedProjectType>ejb</supportedProjectType>
<supportedProjectType>war</supportedProjectType>
<supportedProjectType>wab</supportedProjectType>
<supportedProjectType>bundle</supportedProjectType>
<supportedProjectType>jar</supportedProjectType>
</supportedProjectTypes>
<instructions>
<_include>-osgi.bundle</_include>
</instructions>
</configuration>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
<execution>
<id>bundle-install</id>
<phase>install</phase>
<goals>
<goal>install</goal>
</goals>
</execution>
</executions>
</plugin>
...
使用bnd说明
Web-ContextPath: my-root-http/rest/
Service-Component: *
答案 0 :(得分:5)
OSGi有一部分称为远程服务的规范。在很短的时间内,它的工作方式是您可以使用特殊服务属性注册服务,并且基于属性技术应该获取您的服务并从中创建端点。它不仅涉及REST,还涉及处理远程调用的任何技术。您可以在“远程服务”一章的OSGi Core规范中找到相关信息。
嗯,这是一个规范,但谁实现它?目前我尝试了两个更大的项目。 CXF DOSGi和Eclipse ECF。它们提供了多种支持远程服务规范的技术。基于它在服务器端和客户端的实现,CXF尤其支持Jax-RS。
由于我不想在OSGi中使用特定于Spring的解决方案,所以我最后没有使用CXF,而是创建了自己的解决方案。它基于Jersey和远程服务规范。当使用service.exported.interfaces = *和service.exported.configs = org.everit.osgi.remote.jersey指定OSGi服务时,它将使用HttpService在/ rest / path下创建一个rest端点。你的捆绑包不一定是一个简单的捆绑包。
我必须提一下,如果您通过任何远程服务实现公开您的服务,您应该将Jax-RS注释带入由原始类实现的接口,并基于该接口公开您的服务。
而不是OSGi中的@Resource和@Component注释我建议你应该使用与Spring非常相似的Blueprint(OSGi规范的一部分)。目前Apache Aries和Gemini Blueprint实现了它。使用蓝图,您可以轻松创建bean并将它们相互连接。如果以这种方式注册远程服务,您可以在蓝图的帮助下设置任何属性(就像spring applicationcontext.xml中bean的属性一样)。
您可以找到我在https://source.everit.biz/svn/everit-osgi/trunk/samples/jaxrs/ (用户/密码:来宾/来宾)上创建的示例应用程序。有一个指南解释了如何在http://cookbook.everit.org
启动和开发这些样本我希望示例应用程序可以帮助您开始使用远程服务规范章节。
要了解如何使用JPA和注入(蓝图),您应该检查OSGi概要规范的可能性并找到您喜欢的实现。我还做了一个基于blueprint和hibernate-jpa的示例项目,你可以找到它作为我已经提供的示例网址的兄弟。
<强>更新强>
我在https://github.com/everit-org/osgi-remote-jersey处还有一个JAXRS扩展器实现。有关文档,请参阅自述文件。它与第一种方法的不同之处在于它基于白板服务属性。
答案 1 :(得分:2)
我在OSGi,声明服务和泽西岛遇到了类似的问题。
可以使用@Component和@Reference注释来注释资源。这将指示DS创建SomeResource类的实例,并在满足所有依赖(引用)时将有效引用注入此实例。
您的引用为空的原因是因为JAX-RS实现将为每个Web请求创建SomeResource类的新实例。 SomeResource类的这个实例与DS创建的实例不同。
我通过使用Java静态关键字生成引用变量static来解决这个问题:
private static SomeService service = null;
这确保了依赖引用绑定到类对象而不是实例,然后所有实例都可以看到注入的值。
此解决方案引入了一个新问题。必须在unbind事件(当服务变得不可用时)清除此引用,因为在销毁实例时不会销毁它。
答案 2 :(得分:0)
当@Path注释类型将注册为服务本身时,问题将得到解决。使用DS,您可以注入其他服务。我差不多一年前就遇到过这个问题了。这就是为什么我写了一个小的OSGi JAX-RS连接器,它给出了我所描述的内容。如果您愿意,可以尝试:https://github.com/hstaudacher/osgi-jax-rs-connector