2013-10-01 142 views
5

是否可以为注入到@Named bean的所有会话对象全局设置会话超时?全局设置CDI会话超时

我有几个@ConversationScoped豆类,例如:

import javax.annotation.PostConstruct; 
import javax.enterprise.context.Conversation; 
import javax.enterprise.context.ConversationScoped; 
import javax.inject.Inject; 
import javax.inject.Named; 

@Named 
@ConversationScoped 
public class SomeBean1 { 

    @Inject 
    private Conversation conversation; 

    @PostConstruct 
    private void init() { 
     if (conversation.isTransient()) { 
      conversation.begin(); 
     } 
    } 
} 

@Named 
@ConversationScoped 
public class SomeBean2 { 

    @Inject 
    private Conversation conversation; 

    @PostConstruct 
    private void init() { 
     if (conversation.isTransient()) { 
      conversation.begin(); 
     } 
    } 
}   

这些对话的默认超时为600000毫秒。我想知道是否有什么办法来全局设置对话超时或者我需要

if (!conversation.isTrainsient()) { 
    conversation.setTimeout(MY_CUSTOM_TIMEOUT); 
} 

将其设置在每个bean(问题是,有很多CDI豆并在每个手动设置超时他们的是不是最好的解决办法)

+0

由于以下一些已经证明了问题的答案,有ISN这是一个标准的做法。你所做的任何事情(缺少Stasal的答案)都不是可移植的。 – LightGuard

回答

2

所以,这里是我使用的解决方案(的Oracle WebLogic 12c中,焊缝1.1.Final):

import org.jboss.weld.context.http.HttpConversationContext; 

import javax.inject.Inject; 
import javax.servlet.annotation.WebListener; 
import javax.servlet.http.HttpSessionEvent; 
import javax.servlet.http.HttpSessionListener; 

@WebListener 
public class SessionListener implements HttpSessionListener { 

    @Inject 
    private HttpConversationContext conversationContext; 

    @Override 
    public void sessionCreated(HttpSessionEvent httpSessionEvent) { 
     if (conversationContext != null) { 
      final long DEFAULT_TIMEOUT = 2 * 60 * 60 * 1000; 
      if (conversationContext.getDefaultTimeout() < DEFAULT_TIMEOUT){ 
       conversationContext.setDefaultTimeout(DEFAULT_TIMEOUT); 
      } 
     } 
    } 

    @Override 
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {} 
} 

上下文被注入到监听器中,当用户启动会话时设置超时。

+0

什么时候sessionCreated被调用?这个类是否应该在web.xml中配置? – Emerald214

+0

创建新客户端会话时调用sessionCreated方法。这个类应该在web.xml描述符中配置,或者像上面的代码示例中那样注释(但web.xml中的“metadata-complete”属性应该省略或等于“false”)。关于hadling servlet生命周期事件的更多信息请参见:http://docs.oracle.com/javaee/7/tutorial/servlets002.htm#BNAFJ – stasal

2

有缝/焊接你应该能够做到像下面这样:

@Inject 
private HttpConversationContext conversationContext; 

public void observePreload(@Observes PreloadCompleteEvent event) { 
    //Set global conversation timout to 60000 ms 
    conversationContext.setDefaultTimeout(60000); 
} 

否则我相信你将不得不将它设置为每个会话。

编辑:请注意我用了一个自定义事件,同样可以实现:

public void observePreload(@Observes @Started WebApplication webapp) { 
+0

感谢您的提示,以相同的方式实施此操作,将立即发布解决方案:) – stasal

+0

什么是'PreloadCompleteEvent'? (Weld 2.x)文档中找不到任何关于它的信息。因此,我使用了类似的观察者方法: 'public void observeAppInit(@Observes @Initialized(ApplicationScoped.class)Object event)' 并执行此方法中的工作,该方法按照建议工作。 –

+0

PreloadCompleteEvent是一个自定义事件,使用默认的你也可以做'public void observePreload(@Observes @Started WebApplication webapp){'或者你有什么建议 –

1

这可以用CDI 1.1以便携方式轻松完成。

import javax.enterprise.context.Conversation; 
import javax.enterprise.context.ConversationScoped; 
import javax.enterprise.context.Initialized; 
import javax.enterprise.event.Observes; 
import javax.inject.Inject; 
import javax.servlet.ServletRequest; 

public class ConversationTimeoutDefaultSetter { 

    @Inject 
    private Conversation conversation; 

    public void conversationInitialized(
      @Observes @Initialized(ConversationScoped.class) 
      ServletRequest payload) { 
     conversation.setTimeout(1800000L); // 30 minutes 
    } 

} 

另一个便携式选项是装饰对话。 (警告:未经测试)。

import static javax.interceptor.Interceptor.Priority.APPLICATION; 

import javax.annotation.Priority; 
import javax.decorator.Decorator; 
import javax.decorator.Delegate; 
import javax.enterprise.context.Conversation; 
import javax.inject.Inject; 

@Decorator 
@Priority(APPLICATION) 
public class ConversationTimeoutDefaultSetter implements Conversation, Serializable { 

    private static final long serialVersionUID = 1L; 

    @Inject 
    @Delegate 
    private Conversation delegate; 

    private void setDefaultTimeout() { 
     delegate.setTimeout(1800000L); // 30 minutes 
    } 

    @Override 
    public void begin() { 
     setDefaultTimeout(); 
     delegate.begin(); 
    } 

    @Override 
    public void begin(String id) { 
     setDefaultTimeout(); 
     delegate.begin(id); 
    } 

    @Override 
    public void end() { 
     delegate.end(); 
    } 

    @Override 
    public String getId() { 
     return delegate.getId(); 
    } 

    @Override 
    public long getTimeout() { 
     return delegate.getTimeout(); 
    } 

    @Override 
    public void setTimeout(long milliseconds) { 
     delegate.setTimeout(milliseconds); 
    } 

    @Override 
    public boolean isTransient() { 
     return delegate.isTransient(); 
    } 

} 
+0

您应该列出导入以便更好地理解我的想法。 javax.enterprise.context。初始化是java-ee-api 7的一部分,但是我们例如使用java-ee 6,所以唯一的方法是依靠jboss cdi-api,它比我的解决方案更便携,但仍然不是100% – stasal

+0

@stasal,是的,CDI 1.1实际上是需要这个的。我修改了我的答案。 –

0

您也可以与您当前的HTTP请求的会话超时同步会话Bean的超时:

if (conversation.isTransient()) { 
     conversation.setTimeout(((HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext() 
       .getRequest()).getSession().getMaxInactiveInterval()*1000); 
     conversation.begin(); 
    }