2013-10-01 196 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(); 
    }