在 CDI bean 的非请求环境中获取 JSF ServletContext

Getting JSF ServletContext in non-request environment in a CDI bean

我正在使用 TomEE+ 1.7.1。 使用 JSF 托管 bean,此代码运行良好:

@ManagedBean( eager = true )
@ApplicationScoped
public class AppBean {

    @PostConstruct
    public void init() {
        ServletContext sc = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
        if (GlobalSettings.TESTMODE) {
            sc.getSessionCookieConfig().setDomain("." + GlobalSettings.APP_DOMAIN_TEST);
        } else {
            sc.getSessionCookieConfig().setDomain("." + GlobalSettings.APP_DOMAIN);
        }
    }
}

应用程序启动时的 init 函数 运行 和 ServletContext 可用。

我到处都读到是时候迁移到 CDI bean 而不是 JSF bean 了。所以我想将 @ManagedBean( eager = true ) 更改为 @Named @Eager (@Eager 来自 Omnifaces)。 Init 函数在应用程序启动时 运行,但是没有 FacesContext 所以我无法获取 ServletContext。

一般问题:如何在CDI bean中获取非请求环境下的ServletContext? (ServletContext 不是 'per request' 对象,因此它应该在第一次请求之前存在。)

具体问题:如何在第一次请求发生之前从代码动态设置会话 cookie 的域?

您应该使用 ServletContextListener 来对基于 servlet 的应用程序执行编程配置。

@WebListener
public class Config implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent event) {
        ServletContext servletContext = event.getServletContext(); 
        // ...
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        ServletContext servletContext = event.getServletContext(); 
        // ...
    }

}

A @WebListener 本质上也是 CDI 管理的,因此您可以只使用 @Inject 和那里的朋友。

应用程序范围内的托管 bean 用于保存应用程序范围 data/state,它可以是 used/shared 跨越 requests/views/sessions。

根据 CDI 规范,您可以 @Inject ServletContext 到 CDI bean 中。请务必在 @PostConstruct 中执行此操作,因为注入字段仅在构造后可用:

@Inject ServletContext extCtxt;

@PostConstruct
public void doSomething(){
  // do something with your injected field
}