Liferay 模块(OSGi 捆绑包)停留在“Stopping”
Posted
技术标签:
【中文标题】Liferay 模块(OSGi 捆绑包)停留在“Stopping”【英文标题】:Liferay module (OSGi bundle) stays in "Stopping" 【发布时间】:2018-01-07 23:06:34 【问题描述】:有时当我停止我的 Liferay 模块时(例如,当我将其 JAR 的新版本放入 deploy/
时)模块拒绝停止。
虽然模块应该进入“已解决”状态,但它会永远处于“停止”状态:
通常是由于某个线程未在某处终止,或者网络连接未正确关闭,通常很难调查。
我的问题:如何更有效地找出这个 Liferay 模块的问题是什么?
我尝试了什么:
在 Gogo Shell 中,diag <module id>
似乎没有提供任何有价值的信息来说明模块拒绝离开“停止”状态的原因。
jstack 输出数千行,其中绝大多数在所讨论的 Liferay 模块之外。如果有办法只显示我的模块的 jstack 信息,那就太好了。
【问题讨论】:
您是否在模块中使用了激活器?状态停止意味着 Activator.stop() 方法被调用但尚未返回。你的一个线程应该在那个方法中。 @ChristianSchneider:添加了我的 ServiceActivator。 您在解决 jstack 问题方面做得很好。它创建了一个线程转储,但大多数线程大约有 5-10 行。寻找更大的线程,尤其是其中调用了 ServiceActivator.stop 方法的线程。然后您将看到导致死锁或长时间休眠的原因。 @BalazsZsoldos:寻找 ServiceActivator.stop 是一个很好的提示!你想写一个关于它的答案吗?或者你没时间我可以写。 @NicolasRaoul 我认为查看线程转储并尝试查找代码 sn-p 与其说是真正的答案,不如说是一个建议。如果您想就阻止的原因做出回应,请随意。 【参考方案1】:首先,找到你的 webapp 服务器的 PID:
ps aux | grep tomcat
如果您正在运行除 tomcat 之外的其他服务器,或者如果您有多个实例正在运行,请调整该命令。
然后,将该服务器的所有线程转储到一个文件中:
jstack 12345 > jstack.txt
其中 12345 是您在第一步中找到的 PID。
然后,查看捆绑包的源代码,并找到服务激活器。它通常看起来像这样:
package fr.free.nrw;
[import section]
public class ServiceActivator implements BundleActivator
private ServiceRegistration registration;
@Override
public void start(BundleContext context) throws Exception
registration = context.registerService(
MyService.class.getName(), new MyServiceImpl(), null);
@Override
public void stop(BundleContext context) throws Exception
registration.unregister();
注意:
命名空间, 类名, 停止方法名称。例如在上面的例子中它们是fr.free.nrw
、ServiceActivator
和stop
,从这三个中得到全名fr.free.nrw.ServiceActivator.stop
。
现在打开jstack.txt
并搜索全名。即使文件长达数千行,也很可能只有一次命中,这就是有问题的线程:
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.unregister(ServiceRegistrationImpl.java:222)
at fr.free.nrw.ServiceActivator.stop(ServiceActivator.java:30)
at org.eclipse.osgi.internal.framework.BundleContextImpl$4.run(BundleContextImpl.java:830)
at org.eclipse.osgi.internal.framework.BundleContextImpl$4.run(BundleContextImpl.java:1)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.osgi.internal.framework.BundleContextImpl.stop(BundleContextImpl.java:823)
在这个文件中,向上到段落的开头,这将是这样的:
"fileinstall-/home/nico/p/liferay/osgi/modules" #37 daemon prio=5 os_prio=0 tid=0x00007f39480e3000 nid=0x384f waiting on condition [0x00007f395d169000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000eb8defb8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
有了这些信息,您将知道发生了什么样的线程问题,并且您将能够使用通常的 Java 线程调试技术来解决它 (12)。
【讨论】:
【参考方案2】:您共享的 Activator 永远不应阻塞 stop 方法。所以我怀疑它会导致你描述的行为。
【讨论】:
可以的。 Activator的stop方法是同步调用的。他取消注册服务,这会导致同步服务侦听器(和服务跟踪器)的调用。在 ServiceTracker 上可能会死锁。 啊..有趣。所以原因可能是其他包中的一些写得很糟糕的服务跟踪器或监听器。 可能是。我说的是服务跟踪器级别,但在更高级别上也很容易犯错误。例如:在 DS 组件的服务引用(或激活方法)的设置器中编写一些休眠或等待的业务逻辑。这些代码 sn-ps 通常在服务注册完成时在同一线程上调用,因为它们基于同步服务跟踪器。以上是关于Liferay 模块(OSGi 捆绑包)停留在“Stopping”的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Maven 将第 3 方 OSGi 捆绑包添加到部署包中?
Liferay7 BPM门户开发之38: OSGi Bndtools开发入门
Gradle + OSGi Liferay7 模块,包含传递依赖