程序员们,
我目前正在尝试找到一种简单简洁的方法来获取使用给定接口的服务/组件的列表。我正在使用正在运行的Liferay 7.1.x服务器的gogo-shell,似乎找不到一种简单直接的方法。
我们希望通过 OSGI-configuration 覆盖对所用服务的引用,但首先需要找到使用它的所有组件。 由于存在对服务组件的静态不情愿引用,因此简单地提供具有更高排名的替代方法并不是可行的解决方案。
以下是我正在使用的与gogo相关的捆绑包:
35|Active | 6|Apache Felix Gogo Command (1.0.2)|1.0.2
36|Active | 6|Apache Felix Gogo Runtime (1.1.0.LIFERAY-PATCHED-2)|1.1.0.LIFERAY-PATCHED-2
72|Active | 6|Apache Felix Gogo Shell (1.1.0)|1.1.0
542|Active | 10|Liferay Foundation - Liferay Gogo Shell - Impl (1.0.13)|1.0.13
543|Active | 10|Liferay Gogo Shell Web (2.0.25)|2.0.25
到目前为止,我已经能够通过se (interface=com.liferay.saml.runtime.servlet.profile.WebSsoProfile)
列出接口的所有提供者:
{com.liferay.saml.runtime.profile.WebSsoProfile, com.liferay.saml.runtime.servlet.profile.WebSsoProfile}={service.id=6293, service.bundleid=79, service.scope=bundle, component.name=com.liferay.saml.opensaml.integration.internal.servlet.profile.WebSsoProfileImpl, component.id=3963}
"Registered by bundle:" de.haufe.leong.com.liferay.saml.opensaml.integration [79]
"Bundles using service"
com.liferay.saml.web_2.0.11 [82]
com.liferay.saml.impl_2.0.12 [78]
通过以下方式查看所有捆绑要求:inspect cap service
:
com.liferay.saml.impl_2.0.12 [78] requires:
...
service; com.liferay.saml.runtime.profile.WebSsoProfile, com.liferay.saml.runtime.servlet.profile.WebSsoProfile provided by:
de.haufe.leong.com.liferay.saml.opensaml.integration [79]
...
但是到目前为止,我还没有从这些使用给定接口(或服务组件(的捆绑包中列出实际服务。
到目前为止,我看到的唯一解决方案是通过scr:list bid
列出这些捆绑包的所有服务,然后scr:info componentId
检查每个服务以查看它是否使用 WebSsoProfile 服务。
你们知道使用WebSsoProfile服务查找服务的更快方法吗?
[EDIT]:我们解决了这个问题,而不必为WebSsoProfile服务的所有使用者提供配置覆盖,而是通过在服务器启动时停用默认服务来确保使用我们的实现。您可以看到此处描述的方法。
无论如何,出于调试目的,这种查找将非常有用。 因此,如果有人知道检索接口所有消费者列表的方法,请发布您的解决方案!
标准解决方案是使用inspect
命令。它有一个特殊的服务命名空间。由于服务注册是一项功能,因此可以使用inspect capability service
:
g! inspect c service
org.apache.felix.framework [0] provides:
----------------------------------------
service; org.osgi.service.resolver.Resolver with properties:
service.bundleid = 0
service.id = 1
service.scope = singleton
service; org.osgi.service.packageadmin.PackageAdmin with properties:
service.bundleid = 0
service.id = 2
service.scope = singleton
service; org.osgi.service.startlevel.StartLevel with properties:
service.bundleid = 0
service.id = 3
service.scope = singleton
....
但是,我发现这个命令严重无用。该命令不灵活,输出很糟糕。
然而,Gogo比人们知道的要强大得多。首先,您可以使用捆绑包上下文中的所有方法。
g! servicereferences org.osgi.service.startlevel.StartLevel null
000003 0 StartLevel
如果要查看每个服务的属性:
g! each (servicereferences org.osgi.service.startlevel.StartLevel null) { $it properties }
[service.id=3, objectClass=[Ljava.lang.String;@4acd14d7, service.scope=singleton, service.bundleid=0]
您可以将其转换为内置函数:
g! srv = { servicereferences $1 null }
servicereferences $1 null
g! srv org.osgi.service.startlevel.StartLevel
000003 0 StartLevel
不幸的是,OSGi 在捆绑包上下文中添加了一个重载方法,用于getServiceReferences()
当使用 null 调用时会抛出 NPE。Gogo 对重载的方法很糟糕:-(
但是,使用声明性服务组件添加自己的命令是微不足道的。您可以使用以下内容:
@GogoCommand(scope="service", function="srv")
@Component(service=ServiceCommand.class)
public class ServiceCommand {
@Activate
BundleContext context;
@Descriptor("List all services")
public ServiceReference<?>[] srv() throws InvalidSyntaxException {
return context.getAllServiceReferences(null, null);
}
@Descriptor("List all services that match the name")
public ServiceReference<?>[] srv(
String... names)
throws InvalidSyntaxException {
ServiceReference<?>[] allServiceReferences =
context.getAllServiceReferences(null,null);
if ( allServiceReferences==null)
return new ServiceReference[0];
return Stream.of(allServiceReferences)
.filter(r -> {
String[] objectClass = (String[]) r.getProperty(Constants.OBJECTCLASS);
for (String oc : objectClass) {
for (String name : names)
if (oc.contains(name))
return true;
}
return names.length == 0;
}).sorted().toArray(ServiceReference[]::new);
}
}
这会将srv
命令添加到 Gogo:
g! srv Help Basic
000004 1 Basic
000005 1 Inspect
更新如果要查找哪些捆绑包正在使用特定服务,可以使用:
g! each (srv X) { $it usingbundles }
确保类路径上有以下依赖项:
-buildpath:
org.osgi.service.component.annotations,
org.apache.felix.gogo.runtime,
org.osgi.framework