OSGi/蓝图中的服务引用无法正常工作
我目前有两个 OSGi 捆绑包(bundle1
和 bundle2
),两者都通过 EBA 中的蓝图公开服务。在 bundle2
的 blueprint.xml
中,我想引用 bundle1
中的服务并将其注入到 BuildService 中(代码如下),因为 BuildService 将用于调用 TicketService。然而,这会导致超时异常(也在下文中)。似乎 BuildService 从未在 OSGi 中注册。我该如何做这样的事情?
bundle1
的 blueprint.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:bptx="http://aries.apache.org/xmlns/transactions/v1.0.0">
<bean id="TicketServiceBean" class="com.example.b2.impl.TicketServiceImpl">
<bptx:transaction value="Required" method="*" />
</bean>
<service ranking="0" id="TicketService" interface="com.example.b2.service.TicketService" ref="TicketServiceBean">
<service-properties>
<entry key="service.exported.interfaces" value="*" />
</service-properties>
</service>
</blueprint>
bundle2
的 blueprint.xml
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<bean
id="BuildServiceImplBean"
class="com.example.b1.impl.BuildServiceImpl"
activation="eager" >
<property name="ticketService" ref="TicketServiceRef" />
</bean>
<service
id="BuildService"
ref="BuildServiceImplBean"
interface="com.example.b1.service.BuildService"
activation="eager">
<service-properties>
<entry key="service.exported.interfaces" value="*" />
</service-properties>
</service>
<reference
id="TicketServiceRef"
interface="com.example.b2.service.TicketService"
availability="mandatory"
activation="eager" />
</blueprint>
BuildService 的实现:
public class BuildServiceImpl implements BuildService {
private TicketService ticketService;
@Override
public TicketBuildResponse ticketBuild(TicketBuildRequest ticketBuildRequest) throws BuildServiceException {
//do stuff here
}
public TicketService getTicketService() {
return ticketService;
}
public void setTicketService(TicketService ticketService) {
this.ticketService = ticketService;
}
}
启动应用程序服务器时(Websphere)我得到以下异常:
BlueprintCont E org.apache.aries.blueprint.container.BlueprintContainerImpl$1 run Unable to start blueprint container for bundle com.example.b1.module due to unresolved dependencies [(objectClass=com.example.b2.service.TicketService)]
java.util.concurrent.TimeoutException
at org.apache.aries.blueprint.container.BlueprintContainerImpl$1.run(BlueprintContainerImpl.java:273)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:453)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:315)
at java.util.concurrent.FutureTask.run(FutureTask.java:150)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:207)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:736)
I currently have two OSGi bundles (bundle1
and bundle2
) both both exposing services through a blueprint in an EBA. In bundle2
's blueprint.xml
i want to reference a service from bundle1
and Inject it into the BuildService (code below), as BuildService will be used to call TicketService. This however results in a Timeout exception (also below). It seems like the BuildService never gets registered with OSGi. How would I make something like this work?
blueprint.xml
for bundle1
:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:bptx="http://aries.apache.org/xmlns/transactions/v1.0.0">
<bean id="TicketServiceBean" class="com.example.b2.impl.TicketServiceImpl">
<bptx:transaction value="Required" method="*" />
</bean>
<service ranking="0" id="TicketService" interface="com.example.b2.service.TicketService" ref="TicketServiceBean">
<service-properties>
<entry key="service.exported.interfaces" value="*" />
</service-properties>
</service>
</blueprint>
blueprint.xml
for bundle2
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<bean
id="BuildServiceImplBean"
class="com.example.b1.impl.BuildServiceImpl"
activation="eager" >
<property name="ticketService" ref="TicketServiceRef" />
</bean>
<service
id="BuildService"
ref="BuildServiceImplBean"
interface="com.example.b1.service.BuildService"
activation="eager">
<service-properties>
<entry key="service.exported.interfaces" value="*" />
</service-properties>
</service>
<reference
id="TicketServiceRef"
interface="com.example.b2.service.TicketService"
availability="mandatory"
activation="eager" />
</blueprint>
Implementation of the BuildService:
public class BuildServiceImpl implements BuildService {
private TicketService ticketService;
@Override
public TicketBuildResponse ticketBuild(TicketBuildRequest ticketBuildRequest) throws BuildServiceException {
//do stuff here
}
public TicketService getTicketService() {
return ticketService;
}
public void setTicketService(TicketService ticketService) {
this.ticketService = ticketService;
}
}
When starting up the application server (Websphere) I get the following exception:
BlueprintCont E org.apache.aries.blueprint.container.BlueprintContainerImpl$1 run Unable to start blueprint container for bundle com.example.b1.module due to unresolved dependencies [(objectClass=com.example.b2.service.TicketService)]
java.util.concurrent.TimeoutException
at org.apache.aries.blueprint.container.BlueprintContainerImpl$1.run(BlueprintContainerImpl.java:273)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:453)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:315)
at java.util.concurrent.FutureTask.run(FutureTask.java:150)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:207)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:736)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
解决方案如下:由于默认调用语义不同(本地按引用传递与远程按值传递),OSGi 应用程序运行时以不同方式对待远程服务和本地服务。为了防止应用程序意外调用仅为传递值调用而设计的导出服务,它在本地查找中被隐藏。
解决方案是导出同一个 bean 两次,一次用于远程调用,第二次用于本地。换句话说,您将添加另一个具有相同配置的
元素,但没有service.exported.interfaces
属性。实际上,websphere 中还有一个 osgi 控制台,可以在
[本地 websphere 安装]/profiles/[profileName]/bin/osgiApplicationConsole.bat
下找到。启动后,help()
会为您提供命令列表。要查看从 SCA 导入的服务,您首先连接到您的应用程序(例如connect(2)
),其中应用程序的编号在list()
的结果中给出> 命令)。然后,您可以执行services("(service.imported=true)")
来查看 SCA 添加的服务代理。命令services()
将列出应用程序中的所有服务。Here is the solution: The OSGi applications runtime treats remote services differently from local ones, because of the different default invocation semantics (local pass-by-reference versus remote pass-by-value). To prevent an application accidentally calling an exported service that is only designed for pass-by-value calls, it is hidden from local lookups.
The solution to this is to export the same bean twice, once for remote calls, and the second for local. In other words, you would add another
<service />
element with the same configuration, but without theservice.exported.interfaces
property.There is actually also an osgi console in websphere and it can be found under
[local websphere installation]/profiles/[profileName]/bin/osgiApplicationConsole.bat
. Once lauched,help()
gives you a list of commands. To see your imported services from SCA, you first connect to your application (e.g.connect(2)
, where the number of the application is given in the results of thelist()
command). You can then doservices("(service.imported=true)")
to see the service proxies that have been added by SCA . The commandservices()
will list all the services in the application.