Wildfly 和 Wildfly-swarm 从 war 部署与自定义模块中注入 CDI bean
Wildfly and Wildfly-swarm injecting CDI beans from war deployment vs custom module
在使用 Wildfly-swarm 进行实验的过程中,我 运行 遇到了一个关于 bean 注入的奇怪情况。
我有一个非常简单的 bean,大致是这样的:
@ApplicationScoped
public class FooServiceImpl implements FooService {
Foo delegate;
@PostConstruct public void init() {
delegate = .....;
}
public Foo getFoo() {
return delegate;
}
}
如果我直接在 war 部署中将它捆绑在一个 jar 中,一切都会按预期正常工作。但是,我需要此实现的内部部分与应用程序完全隔离,这就是为什么我将服务 api 及其实现打包到单独的 jboss 模块中。
这些模块被添加到 swarm uberJar 中,我的应用程序通过 MANIFEST Dependencies 条目依赖于它们。现在,一切似乎都正常,FooService bean 已注入我的应用程序 servlet/rest 资源中,但未调用 init() 方法。
我不知道这里发生了什么。这就像 bean 解析过程无法识别 @ApplicationScope 注释。可以有两个不同的 class 装载机吗?
更新
我启用了跟踪,在我看来 Weld 正在将 FooImpl class 视为 ApplicationScoped,即向正在创建的代理添加 LifecycleMixin.lifecycle_mixin_$$_postConstruct()
:
2017-09-14 23:11:34,315 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001538: Created context instance for bean Managed Bean [class com.xxx.FooImpl] with qualifiers [@Any @Default] identified as WELD%ManagedBean%test.war|test.war.external.file:/tmp/nestedjarloader2449602760983533131.tmp/META-INF/beans.xml|com.xxx.FooImpl|null|false
2017-09-14 23:11:34,315 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001542: Retrieving/generating proxy class com.xxx.FooImpl$Proxy$_$$_WeldClientProxy
2017-09-14 23:11:34,315 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public void com.xxx.FooImpl.registerMessageHandler(com.xxx.MessageHandler)
2017-09-14 23:11:34,315 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public void com.xxx.FooImpl.registerListeners(java.util.EventListener[])
2017-09-14 23:11:34,316 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public void com.xxx.FooImpl.send(com.xxx.MessageHandler,com.xxx.Message) throws java.io.IOException
2017-09-14 23:11:34,316 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public void com.xxx.FooImpl.init()
2017-09-14 23:11:34,316 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public java.lang.String java.lang.Object.toString()
2017-09-14 23:11:34,316 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public abstract void org.jboss.weld.interceptor.proxy.LifecycleMixin.lifecycle_mixin_$$_postConstruct()
2017-09-14 23:11:34,316 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public abstract void org.jboss.weld.interceptor.proxy.LifecycleMixin.lifecycle_mixin_$$_preDestroy()
2017-09-14 23:11:34,317 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001543: Created Proxy class of type class com.xxx.FooImpl$Proxy$_$$_WeldClientProxy supporting interfaces [interface com.xxx.FooService, interface java.io.Serializable, interface org.jboss.weld.interceptor.proxy.LifecycleMixin, interface org.jboss.weld.interceptor.util.proxy.TargetInstanceProxy, interface org.jboss.weld.bean.proxy.ProxyObject]
2017-09-14 23:11:34,317 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001506: Created new client proxy of type class com.xxx.FooImpl$Proxy$_$$_WeldClientProxy for bean Managed Bean [class com.xxx.FooImpl] with qualifiers [@Any @Default] with ID WELD%ManagedBean%test.war|test.war.external.file:/tmp/nestedjarloader2449602760983533131.tmp/META-INF/beans.xml|com.xxx.FooImpl|null|false
2017-09-14 23:11:34,318 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001507: Located client proxy of type class com.xxx.FooImpl$Proxy$_$$_WeldClientProxy for bean Managed Bean [class com.xxx.FooImpl] with qualifiers [@Any @Default]
未调用构造后拦截器 -- 为什么?谜团加深!
更新 2
在 vanilla wildfly 上测试过,行为相同,如果 bean 位于模块中,则不会调用 @PostConstruct 方法。
我想这个问题和 the one in JBoss forums 是有联系的,但万一它们不是...
可能的原因是 您的独立模块没有声明对 <module name="javax.annotation.api"/>
的依赖,而 @PostConstruct
正是来自于此。添加它,应该可以解决问题。
这似乎是预期的 JVM 行为 (as explained in this SO question) - 如果您在运行时错过了依赖项,程序仍将执行但忽略注释。
作为解决此问题的方法(如果上述方法不起作用或您做不到)- 您可以使用初始化方法。是CDI一创建对象就执行的方法。
在使用 Wildfly-swarm 进行实验的过程中,我 运行 遇到了一个关于 bean 注入的奇怪情况。
我有一个非常简单的 bean,大致是这样的:
@ApplicationScoped
public class FooServiceImpl implements FooService {
Foo delegate;
@PostConstruct public void init() {
delegate = .....;
}
public Foo getFoo() {
return delegate;
}
}
如果我直接在 war 部署中将它捆绑在一个 jar 中,一切都会按预期正常工作。但是,我需要此实现的内部部分与应用程序完全隔离,这就是为什么我将服务 api 及其实现打包到单独的 jboss 模块中。
这些模块被添加到 swarm uberJar 中,我的应用程序通过 MANIFEST Dependencies 条目依赖于它们。现在,一切似乎都正常,FooService bean 已注入我的应用程序 servlet/rest 资源中,但未调用 init() 方法。
我不知道这里发生了什么。这就像 bean 解析过程无法识别 @ApplicationScope 注释。可以有两个不同的 class 装载机吗?
更新
我启用了跟踪,在我看来 Weld 正在将 FooImpl class 视为 ApplicationScoped,即向正在创建的代理添加 LifecycleMixin.lifecycle_mixin_$$_postConstruct()
:
2017-09-14 23:11:34,315 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001538: Created context instance for bean Managed Bean [class com.xxx.FooImpl] with qualifiers [@Any @Default] identified as WELD%ManagedBean%test.war|test.war.external.file:/tmp/nestedjarloader2449602760983533131.tmp/META-INF/beans.xml|com.xxx.FooImpl|null|false
2017-09-14 23:11:34,315 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001542: Retrieving/generating proxy class com.xxx.FooImpl$Proxy$_$$_WeldClientProxy
2017-09-14 23:11:34,315 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public void com.xxx.FooImpl.registerMessageHandler(com.xxx.MessageHandler)
2017-09-14 23:11:34,315 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public void com.xxx.FooImpl.registerListeners(java.util.EventListener[])
2017-09-14 23:11:34,316 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public void com.xxx.FooImpl.send(com.xxx.MessageHandler,com.xxx.Message) throws java.io.IOException
2017-09-14 23:11:34,316 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public void com.xxx.FooImpl.init()
2017-09-14 23:11:34,316 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public java.lang.String java.lang.Object.toString()
2017-09-14 23:11:34,316 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public abstract void org.jboss.weld.interceptor.proxy.LifecycleMixin.lifecycle_mixin_$$_postConstruct()
2017-09-14 23:11:34,316 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001541: Adding method to proxy: public abstract void org.jboss.weld.interceptor.proxy.LifecycleMixin.lifecycle_mixin_$$_preDestroy()
2017-09-14 23:11:34,317 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001543: Created Proxy class of type class com.xxx.FooImpl$Proxy$_$$_WeldClientProxy supporting interfaces [interface com.xxx.FooService, interface java.io.Serializable, interface org.jboss.weld.interceptor.proxy.LifecycleMixin, interface org.jboss.weld.interceptor.util.proxy.TargetInstanceProxy, interface org.jboss.weld.bean.proxy.ProxyObject]
2017-09-14 23:11:34,317 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001506: Created new client proxy of type class com.xxx.FooImpl$Proxy$_$$_WeldClientProxy for bean Managed Bean [class com.xxx.FooImpl] with qualifiers [@Any @Default] with ID WELD%ManagedBean%test.war|test.war.external.file:/tmp/nestedjarloader2449602760983533131.tmp/META-INF/beans.xml|com.xxx.FooImpl|null|false
2017-09-14 23:11:34,318 TRACE [org.jboss.weld.Bean] (ServerService Thread Pool -- 12) WELD-001507: Located client proxy of type class com.xxx.FooImpl$Proxy$_$$_WeldClientProxy for bean Managed Bean [class com.xxx.FooImpl] with qualifiers [@Any @Default]
未调用构造后拦截器 -- 为什么?谜团加深!
更新 2
在 vanilla wildfly 上测试过,行为相同,如果 bean 位于模块中,则不会调用 @PostConstruct 方法。
我想这个问题和 the one in JBoss forums 是有联系的,但万一它们不是...
可能的原因是 您的独立模块没有声明对 <module name="javax.annotation.api"/>
的依赖,而 @PostConstruct
正是来自于此。添加它,应该可以解决问题。
这似乎是预期的 JVM 行为 (as explained in this SO question) - 如果您在运行时错过了依赖项,程序仍将执行但忽略注释。
作为解决此问题的方法(如果上述方法不起作用或您做不到)- 您可以使用初始化方法。是CDI一创建对象就执行的方法。