我试图从payara/micro:4.181迁移到payara/mecro:5.222.3,我注意到在Jar文件中没有调用带有observer[@initialized(ApplicationScoped.class(ServletContext init]的初始化方法。
public void init(@Observes @Initialized(ApplicationScoped.class) ServletContext init)
不过,当使用payara/micro:4.181时,它会被正确调用。
再现所描述的行为:
- 从github_link_to_illustration_files下载所附的reproduct_observer_sissue.zip
- 将文件解压缩到";current_dir";解压缩后的文件包含一个Dockerfile,内容如下:
#FROM payara/micro:5.2022.3
FROM payara/micro:4.181
COPY app.war $DEPLOY_DIR
取消注释与要运行应用程序的payara/micro版本对应的行。
- 运行以下docker命令来部署应用程序:
- docker build-t repissue:v1
- docker运行repissue:v1
- 如果您检查路径";current_dir\sources\libs\lib\src\main\java\mylib\Library.java"您可以看到它包含两个init方法,但是在payara/micro:5.222.3上部署时,不会调用init(@observes@initialized(ApplicationScoped.class(ServletContext init((检查日志(
package mylib;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
import javax.servlet.ServletContext;
@ApplicationScoped
public class Library {
public boolean someLibraryMethod() {
return true;
}
public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
System.out.println(" ### log-1 mylib.Library.init(java.lang.Object) called ###");
}
public void init(@Observes @Initialized(ApplicationScoped.class) ServletContext init) {
System.out.println(" ### log-2 mylib.Library.init(javax.servlet.ServletContext) invoked ###");
}
}
提前感谢的任何最终回复/提示
我认为对@Observes @Initialized(ApplicationScoped.class)
的期望存在误解。JakartaEE的规格(8(说:
初始化上下文时,即准备使用时,会触发具有此限定符的事件。
并且">上下文";这里指的是CDI上下文,而ServletContext
绝对不是。
此外,我没有发现任何关于事件消息类型的文档。因此,这完全是特定于实现的,不应该对此进行任何假设(如果您想保持代码的可移植性(。
如果您的Library
对象在Payara 4中两次接收到该事件(一次使用Object
,一次使用ServletContext
(,则这可能被视为该平台的错误(更不用说bug(。
如果您希望收到服务器启动的通知并在该阶段获得ServletContext
,我建议您实现javax.servlet.ServletContainerInitializer
或javax.servlet.ServletContextListener
。ServletContextListener
(相对于其他(的最大优势是可以轻松地与CDIBean(@ApplicationScoped
或@Singleton
(交互。
这里有一个例子:
package mylib;
import javax.inject.Inject;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class MyListener implements ServletContextListener {
@Inject
Library library;
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println(" ### log-4 mylib.MyListener.contextInitialized() invoked ###");
System.out.println(sce.getServletContext());
System.out.println(library);
System.out.println(library.someLibraryMethod());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println(" ### log-5 mylib.MyListener.contextDestroyed() invoked ###");
System.out.println(sce.getServletContext());
}
}
(使用Docker项目进行测试(
希望这能有所帮助。
更新
我还发现了以下Gist,这似乎正是你想要实现的:https://gist.github.com/mojavelinux/637959
注意,这里@Initialized
和@Destroyed
是自定义限定符,而不是来自包javax.enterprise.context
的限定符。
此外,这里还有使用javax.enterprise.context
限定符的Gist的更新版本:https://gist.github.com/nineninesevenfour/d9c643ff5a7f98302f89687720d0a138.这样一来,Library
的原始代码就可以保持不变。
然而,在更新的Gist中,这两个方法被调用了两次(一次来自Payara,一次来自ServletContextLifecycleNotifier
:
// Library.java
public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
System.out.println(" ### log-1 mylib.Library.init(java.lang.Object) called ###");
}
// App.java
public static void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
System.out.println(new App().getGreeting());
}