美文网首页我爱编程
Spring 绑定有状态对象到线程

Spring 绑定有状态对象到线程

作者: ilaoke | 来源:发表于2018-04-13 17:29 被阅读104次

问题背景

Spring中,在Bean默认为单例的前提下,如果需要在Controller和Services之间频繁传递一个有状态对象时,总是通过方法形参传递,是否不够优雅?如果是,那就continue,如果无所谓,就return.

解决方法

使用ThreadLocalTargetSource,设置被代理对象(target bean),每个线程在操作target bean时,都是处理绑定在当前线程的对象,其原理是 代理 + ThreadLocal。

注意事项

在request结束时,要清理被代理对象的状态,这里利用filter来实现。

代码

配置ThreadLocalTargetSource以及Filter

@Configuration
public class AppConfig {

    @Bean
    public Filter transactionLogFilter() {
        return new TransactionLogFilter();
    }

    @Bean
    public FilterRegistrationBean tenantFilterRegistration() {
        FilterRegistrationBean result = new FilterRegistrationBean();
        result.setFilter(transactionLogFilter());
        result.setUrlPatterns(Collections.singletonList("/*"));
        result.setName("Transaction Log Filter");
        result.setOrder(1);
        return result;
    }

    @Bean(destroyMethod = "destroy")
    public ThreadLocalTargetSource threadLocalTenantStore() {
        ThreadLocalTargetSource threadLocalTargetSource = new ThreadLocalTargetSource();
        threadLocalTargetSource.setTargetBeanName("transactionLogStore");
        return threadLocalTargetSource;
    }

    @Primary
    @Bean(name = "proxiedThreadLocalTargetSource")
    public ProxyFactoryBean proxiedThreadLocalTargetSource(ThreadLocalTargetSource threadLocalTargetSource) {
        ProxyFactoryBean result = new ProxyFactoryBean();
        result.setTargetSource(threadLocalTargetSource);
        return result;
    }

    @Bean(name = "transactionLogStore")
    @Scope(scopeName = "prototype") // 注意此处是prototype,在需要Bean时,为每个线程创建各自的实例
    public TransactionLogStore transactionLogStore() {
        return new TransactionLogStore();
    }

}

Filter

public class TransactionLogFilter implements Filter {

    @Autowired
    TransactionLogStore transactionLogStore;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String v = request.getParameter("v");
        try {
            transactionLogStore.init(v);
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            // 注意此处要清理被代理对象的状态,避免当前线程在被下一个请求使用时保留有上一个请求的状态
            transactionLogStore.clear();
        }
    }

    @Override
    public void destroy() {

    }
}
public class TransactionLogStore {

    private String logId;

    private TTransactionLog transactionLog;

    public void init(String v) {
        transactionLog = new TTransactionLog();
        logId = v;
    }

    public void clear() {
        logId = null;
        transactionLog = null;
    }
    // ... set get
}

Ref:
http://tech.asimio.net/2017/11/28/An-alternative-to-ThreadLocal-using-Spring.html

相关文章

  • Spring 绑定有状态对象到线程

    问题背景 Spring中,在Bean默认为单例的前提下,如果需要在Controller和Services之间频繁传...

  • 理解ThreadLocal

    Spring容器中的单例Bean是否线程安全? 有状态对象(Stateful Bean) :就是有实例变量的对象,...

  • hibernate详解(五)Session常见的优化方式

    将session对象与当前线程进行绑定,因为session是线程不安全的,所以必须将session与当前线程进行绑...

  • 【Java】线程间的状态转换

    线程状态图 线程间的状态转换 新建(new):新创建了一个线程对象 可运行(runnable):线程对象创建后,其...

  • java多线程关系

    注:一个对象可有多个线程 就绪状态会有不同对象的线程 一般就绪状态是线程持有锁的(推理),若回到就绪状态线程发现目...

  • 彻底搞懂Java的等待-通知(wait-notify)机制

    线程的生命周期转换 新建状态(New):新建一个线程对象。 就绪/可运行状态(Runnable):线程对象创建后,...

  • 1_基础知识_chapter03_对象的共享_1_可见性

    (1)内存可见性一个线程修改了对象状态后, 其他线程能够看到发生的状态变化(2) 重排序在其他线程中,可以观察到某...

  • java线程状态

    1、新建状态(New):新创建了一个线程对象。 2、就绪状态(Runnable):线程对象创建后,其他线程调用了该...

  • Java基础知识(三)

    一、线程状态转化 线程状态生命周期如下: 新建状态(New):新创建了一个线程对象。 就绪状态(Runnable)...

  • 线程的学习总结

    我打算从线程得生命周期开始总结多线程: 线程的生命周期: 新建状态:线程对象创建之后,线程进入新建状态. 就绪状态...

网友评论

    本文标题:Spring 绑定有状态对象到线程

    本文链接:https://www.haomeiwen.com/subject/trhhkftx.html