英文:
OSGI Service visibility/DS annotation component injection
问题
以下是您提供的内容的中文翻译部分:
我有一个由Apache Felix Dependency Manager实例化的服务,因为我需要使用工厂方法来返回实现:
manager.add(
manager.createComponent()
.setInterface(aServiceName, new Properties())
.setFactory(factory, "create"));
因为我希望将此服务注入到同一捆绑包中的另一个服务中,aService和bService都需要位于同一捆绑包中:
@Component
public class BService {
@Reference
private AService aService;
[...]
}
这个工作得非常好,问题在于我不希望aService在捆绑包外可见,就像一个私有服务一样。
如果我移除:
.setInterface(aServiceName, new Properties())
该组件<strike>似乎仍然会被创建</strike>未被创建,并且未注册为服务,因此不能在其他捆绑包中使用,但我不能使用DS注解来注入该组件。
难道真的不能使该服务仅在产生它的捆绑包内可见吗?还是有一种方法可以使用DS注解仍然注入组件?
我尝试使用Apache Felix Dependency Manager来注入组件:
import org.apache.felix.dm.annotation.api.Component;
import org.apache.felix.dm.annotation.api.ServiceDependency;
@Component
public class BService {
@ServiceDependency
private AService aService;
[...]
}
但我发现该组件未被注入:
[32] org.apache.felix.dependencymanager.runtime
[0] org.apache.felix.dm.runtime.DependencyManagerRuntime registered
active (DependencyManager-Component=*) bundle optional available
org.osgi.service.packageadmin.PackageAdmin service required available
org.osgi.service.log.LogService service optional available
[131] [...]
[7] [...].BService unregistered
org.osgi.service.log.LoggerFactory service required available
[...].AService service required unavailable
这是否意味着我不能使用@ServiceDependency注入简单的组件,因为它们必须是服务,因此必须在OSGI注册表中?那么如何使用注解注入简单组件?应该有一种方法,对吗?
更新:
我刚意识到aService的实现需要导出该包,因此这只是一个设计缺陷。然后我简单地找到了一种将服务分隔到两个不同捆绑包中的方法(OSGI方式),并解决了我的问题。
在这之前,我尝试从导出的捆绑包中移除该包,但仍然不起作用,该服务仍然可用。
Export-Package: [...].services;version="0.0.1"
Provide-Capability: osgi.service;uses:="[...].services";objectClass="[...].services.BService",osgi.service;uses="[...].services.internal";objectClass="[...].services.internal.AService"
Require-Capability: osgi.extender;filter="(&(osgi.extender=osgi.component)(version>=1.4.0)(!(version>=2.0.0)))",osgi.service;effective:=active;filter="(objectClass=[...].services.internal.AService)"
英文:
I have a service instantiated by Apache Felix Dependency Manager, because I need to use a factory method to return the implementation:
manager.add(
manager.createComponent()
.setInterface(aServiceName, new Properties())
.setFactory(factory, "create"));
because I want this service to be injected into a service inside the same bundle, both aService and bService need to be in the same bundle:
@Component
public class BService {
@Reference
private AService aService;
[...]
}
This is working perfectly fine, the thing is that I don't want aService to be visible outside the bundle, like a private service.
If I remove:
.setInterface(aServiceName, new Properties())
the component <strike>seems to be created anyway</strike> is not created and it's not registered as a service and thus is not available to other bundles, but I can't use DS annotation to inject the component.
Is really not possible to make the service only visible inside the bundle that originated it? Or is there a way to still inject the component with DS annotation?
I tried using Apache Felix Dependency Manager to inject the component:
import org.apache.felix.dm.annotation.api.Component;
import org.apache.felix.dm.annotation.api.ServiceDependency;
@Component
public class BService {
@ServiceDependency
private AService aService;
[...]
}
but I found out the component is not injected:
[32] org.apache.felix.dependencymanager.runtime
[0] org.apache.felix.dm.runtime.DependencyManagerRuntime registered
active (DependencyManager-Component=*) bundle optional available
org.osgi.service.packageadmin.PackageAdmin service required available
org.osgi.service.log.LogService service optional available
[131] [...]
[7] [...].BService unregistered
org.osgi.service.log.LoggerFactory service required available
[...].AService service required unavailable
Does this mean I can't inject simple component with @ServiceDependency because they have to be services and thus in the OSGI registry? How then can I inject simple components using annotation? It should there be one, right?
UPDATE
I've just realised that the aService implementation requires the package to be exported, therefore it was just a design flaw. Then I simply have found a way to separate the services in two different bundles (the OSGI way) and solved my issue.
Before doing that I tried removing the package from the exported bundle, but still didn't work, the service would still be available.
Export-Package: [...].services;version="0.0.1"
Provide-Capability: osgi.service;uses:="[...].services";o
bjectClass="[...].services.BService",osgi.service;uses:=
"[...].services.internal";objectClass="[...].services.internal.AService"
Require-Capability: osgi.extender;filter:="(&(osgi.extender=osgi.compo
nent)(version>=1.4.0)(!(version>=2.0.0)))",osgi.service;effective:=ac
tive;filter:="(objectClass=[...].services.internal.AServ
ice)"
答案1
得分: 1
创建一个仅在捆绑包内可见的服务,只需确保不导出服务接口的包。这样,其他捆绑包将无法看到或使用该服务。
英文:
To create a service that is only visible inside the bundle simply make sure you do not export the package of the service interface. This way other bundles will not see or use the service.
答案2
得分: 1
确实,只有将服务发布到OSGi服务注册表中,服务注入才能起作用。为了解决这个问题,您可以考虑将您的“aService”设置为包私有,而不是导出它。这样,aService 将只能从您的 bundle 内部声明的组件中可见。
或许您还可以考虑使用相同的旧的 “new” 关键字来连接您的内部组件(作为您的 bundle 的一部分)?请查看 Peter Kriens 在关于服务组件可见性的这个有趣回答:
https://www.mail-archive.com/users@felix.apache.org/msg16349.html
希望这有所帮助。
顺祝安好,
皮埃尔
英文:
Indeed, services injections will only work if services are published to the OSGi service registry. To work around, you could consider to make your "aService" package private to the bundle, and not export it. In this way, the aService will be only visible from the components declared inside your bundle.
Now, maybe you could also consider to wire your internal components (being part of your bundle) using the same old "new" keyword ? Please take a look at this interesting response from Peter Kriens regarding service components visibility:
https://www.mail-archive.com/users@felix.apache.org/msg16349.html
Hope this helps ?
kind regards
Pierre
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论