我试图从payara/micro:4.181迁移到payara/微:5.2022.3,并且我注意到带有观察者@initialized(ApplicationScoped.class) ServletContext init的初始化方法不会在Jar文件中调用。
public void init(@Observes @Initialized(ApplicationScoped.class) ServletContext init)但是,当使用payara/micro:4.181时,就会正确地调用它。
复制所描述的行为:
#FROM payara/micro:5.2022.3
FROM payara/micro:4.181
COPY app.war $DEPLOY_DIR取消与要运行应用程序的payara/微版本对应的行的注释。
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 ###");
}
}预先感谢任何最终的答复/暗示。
发布于 2022-10-08 21:41:01
我认为人们对@Observes @Initialized(ApplicationScoped.class)的期望存在误解。JakartaEE规范(8)说:
具有此限定符的事件将在初始化上下文时触发,即准备使用。
这里的“上下文”指的是CDI上下文,而ServletContext绝对不是。
另外,我没有发现任何关于事件消息的类型的文档。因此,这完全是特定于实现的,不应该对其进行任何假设(如果您希望保持代码可移植性)。
如果您的Library对象在Payara 4中两次收到该事件(一次使用Object,一次使用ServletContext),那么这可以被认为是该平台的一个错误(更不用说bug)。
我建议您要么实现一个javax.servlet.ServletContainerInitializer,要么实现一个javax.servlet.ServletContextListener,如果您想得到服务器启动的通知,并在这个阶段获得ServletContext。ServletContextListener的最大优点是您可以轻松地与CDI (@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:https://gist.github.com/nineninesevenfour/d9c643ff5a7f98302f89687720d0a138的限定符的Gist的更新版本。这样,您的原始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());
}https://stackoverflow.com/questions/73911937
复制相似问题