【问题标题】:Setting and getting session-bound attribute in spring在春季设置和获取会话绑定属性
【发布时间】:2012-10-02 14:43:36
【问题描述】:

我在 Spring 中关注了 dynamic datasource routing 教程。为此,我必须扩展 AbstractRoutingDataSource 以告诉 spring 要获取哪个数据源,所以我这样做了:

public class CustomRouter extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return CustomerContextHolder.getCustomerType();
    }
}

一切都很好,直到我找到负责保持 customerType 值的类(在整个会话期间它应该是相同的):

    public class CustomerContextHolder {

        private static final ThreadLocal<Integer> contextHolder = new ThreadLocal<Integer>(); 

        public static void setCustomerType(Integer customerType) {
            contextHolder.set(customerType);
        } 
        public static Integer getCustomerType() {
            return (Integer) contextHolder.get();
        }
        public static void clearCustomerType() {
            contextHolder.remove();
        }
    }

这会创建一个线程绑定变量customerType,但我有一个带有spring 和JSF 的Web 应用程序,我认为不是线程而是会话。所以我用线程A(视图)在登录页面中设置它,但随后线程B(Hibernate)请求该值以知道要使用什么数据源,它是@987654324 @ 确实,因为它对这个线程有一个新的价值。

有什么方法可以做到 Session-bounded 而不是 Thread-bounded?

到目前为止我尝试过的事情:

  • 在视图中注入 CustomRouter 以在会话中设置它:不起作用,它会导致依赖项中的循环
  • ThreadLocal 替换为整数:不起作用,该值始终由最后登录的用户设置

【问题讨论】:

  • 为什么休眠在另一个线程中执行?
  • 不应该吗?当我调试 DAO 方法时,我看到每次都有不同的线程访问该方法。这是错的吗?
  • 据我所知,servlet 容器对每个请求使用一个线程,这意味着当发出 HTTP 请求时,会从池中创建或检索一个线程来为其提供服务,并且只有一个线程。因此,仅当该线程正在处理不同的请求时,访问该方法的不同线程才可以。
  • 这就是为什么它有不同的值,因为对于一个新线程,我猜会创建一个新的 ThreadLocal。所以我需要以某种方式将它存储在会话中,这在请求之间是持久的
  • ThreadLocals 不会在新线程运行时创建。相反,它存储了一个引用线程的新值。

标签: java spring thread-safety multi-tenant


【解决方案1】:

FacesContext.getCurrentInstance() 工作了吗?如果是这样,那么你可以试试这个:

public class CustomerContextHolder { 

    private static HttpSession getCurrentSession(){
             HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance()
                 .getExternalContext().getRequest();

             return request.getSession();
    }

    public static void setCustomerType(Integer customerType) {

       CustomerContextHolder.getCurrentSession().setAttribute("userType", customerType);

    }

    public static Integer getCustomerType() {

        return (Integer) CustomerContextHolder.getCurrentSession().getAttribute("userType");
    }

    public static void clearCustomerType() {
        contextHolder.remove(); // You may want to remove the attribute in session, dunno
    }
}

【讨论】:

    猜你喜欢
    • 2021-04-20
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多