如何从过滤器中获取 SessionScoped CDI bean?

Posted

技术标签:

【中文标题】如何从过滤器中获取 SessionScoped CDI bean?【英文标题】:How do I get a SessionScoped CDI bean from inside a Filter? 【发布时间】:2011-12-10 13:07:59 【问题描述】:

此问题与writing a session timeout handler 上的上一个问题有关。

该线程中的答案涉及从 servlet 访问各种会话范围的托管 bean。建议(如 here 所示)是在过滤器中执行此操作:

HttpSession session = request.getSession(false);
User user = (session != null) ? (User) session.getAttribute("user") : null;

大概这会获取 User 类的会话 bean。问题是这不起作用。

问题在于 bean 存在于会话属性中,但它们是由 Weld 工具包装的。我写了 doFilter() 方法如下:

public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain)
        throws IOException, ServletException 
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;

    String sp = req.getServletPath();
    System.out.println("------------------------");
    System.out.println("doFilter(): " + sp);

    if (!sp.startsWith("/javax"))   // eliminates many requests
        HttpSession session = req.getSession();
        Enumeration<String> en = session.getAttributeNames();
        int count = 0;            
        while (en.hasMoreElements()) 
            String e = en.nextElement();
            System.out.println("Attribute " + ++count + ": " + e);
        
    
    chain.doFilter(request, response);

当这转储会话属性时,我通常会得到这样的结果:

INFO: ------------------------
INFO: doFilter(): /Display.xhtml
INFO: Attribute 1: org.jboss.weld.context.http.HttpSessionContext#org.jboss.weld.bean-WEB-INF/lib/myfaces-extcdi-bundle-jsf20-1.0.1-ManagedBean-class org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.EditableWindowContextManagerProxy
INFO: Attribute 2: org.jboss.weld.context.http.HttpSessionContext#org.jboss.weld.bean-MyApp5-ManagedBean-class com.app.Login
INFO: Attribute 3: org.jboss.weld.context.conversation.ConversationIdGenerator
INFO: Attribute 4: com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap
INFO: Attribute 5: org.jboss.weld.context.ConversationContext.conversations
INFO: Attribute 6: facelets.ui.DebugOutput
INFO: Attribute 7: javax.faces.request.charset
INFO: Attribute 8: org.apache.myfaces.extensions.cdi.core.api.scope.conversation.WindowContext:EXISTING_WINDOW_ID_LIST

属性 #2 似乎代表了我想要的 bean。不用说,调用 session.getAttribute("login") 不起作用。

谁能说出如何访问底层托管 bean?我更愿意以一种与 Weld 无关的方式来做这件事,但这可能是不可能的。

【问题讨论】:

【参考方案1】:

此方法仅适用于会话范围的 JSF @ManagedBean,不适用于 CDI @Named bean。

你需要@Inject它作为过滤器的一个属性。

@Inject
private User user;

【讨论】:

BalusC 你睡过吗?我刚刚尝试用 @Named 注释我的过滤器,并为我的 Login bean 做一个 @Inject。有效!我不知道 CDI 服务会在 Filter 中工作。我想这意味着 Filter 对象在每个请求周期都被实例化,而不仅仅是在 Servlet 的生命周期内实例化一次。 现在只有 21:02 :) 如果您使用 @WebFilter 注释过滤器,它应该可以工作。我宁愿不让它@Named(同样,@Inject 也应该在@WebServlet servlet 中工作)。 CDI 更像是一个代理。对象是在线程本地注入的,要注入的实例不需要具有相同或更广泛的范围。 @BalusC: 当user 成为过滤器的成员变量时,这个解决方案线程安全吗? @Toru: 除非你不省略@Inject【参考方案2】:
import org.jboss.weld.context.SerializableContextualInstanceImpl;

    HttpSession httpSession = (HttpSession) facesContext.getExternalContext().getSession(false);
    Enumeration<String> attribs = httpSession.getAttributeNames();
    String attrib = null;
    while (attribs.hasMoreElements())          
        attrib = attribs.nextElement();
        Object obj = httpSession.getAttribute(attrib);
        if(obj instanceof SerializableContextualInstanceImpl)
            SerializableContextualInstanceImpl impl = (SerializableContextualInstanceImpl)obj;
            //here: MyObject myObj= (MyObject)impl.getInstance();
                   
    

【讨论】:

以上是关于如何从过滤器中获取 SessionScoped CDI bean?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不应该将 JSF SessionScoped bean 用于逻辑?

为啥 f:validateDoubleRange 仅适用于 @SessionScoped?

如何使用 Objective C 从 iOS 中的 Core Data 中过滤数据

如何从 chrome 获取打开的标签列表? | C#

@SessionScoped 是一个好习惯吗? [复制]

sessionscoped 托管 bean 与有状态 ejb