十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
这篇文章主要为大家展示了“怎么解决Spring session监听导致创建大量redisMessageListenerContailner-X线程问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“怎么解决Spring session监听导致创建大量redisMessageListenerContailner-X线程问题”这篇文章吧。
成都创新互联公司长期为1000多家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为巫山企业提供专业的成都网站建设、网站设计,巫山网站改版等技术服务。拥有十多年丰富建站经验和众多成功案例,为您定制开发。
待解决的问题
Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程
解决办法
为spring session添加springSessionRedisTaskExecutor线程池。
/** * 用于spring session,防止每次创建一个线程 * @return */ @Bean public ThreadPoolTaskExecutor springSessionRedisTaskExecutor(){ ThreadPoolTaskExecutor springSessionRedisTaskExecutor = new ThreadPoolTaskExecutor(); springSessionRedisTaskExecutor.setCorePoolSize(8); springSessionRedisTaskExecutor.setMaxPoolSize(16); springSessionRedisTaskExecutor.setKeepAliveSeconds(10); springSessionRedisTaskExecutor.setQueueCapacity(1000); springSessionRedisTaskExecutor.setThreadNamePrefix("Spring session redis executor thread: "); return springSessionRedisTaskExecutor; }
原因
在Spring Session(redis)的配置类源码中(RedisHttpSessionConfiguration):
@Autowired( required = false //该处理监听的线程池不是必须的,如果不自定义默认将使用SimpleAsyncTaskExecutor线程池 ) @Qualifier("springSessionRedisTaskExecutor") public void setRedisTaskExecutor(Executor redisTaskExecutor) { this.redisTaskExecutor = redisTaskExecutor; }
springSessionRedisTaskExecutor不是必须的,如果不自定义则spring默认将使用SimpleAsyncTaskExecutor线程池。
题外话
SimpleAsyncTaskExecutor:每次都将创建新的线程(说是“线程池”,其实并非真正的池化,但它可以设置最大并发线程数量。)
@EnableAsync开启异步方法,背后默认使用的就是这个线程池。使用异步方法时如果业务场景存在频繁的调用(该异步方法),请自定义线程池,以防止频繁创建线程导致的性能消耗。如果该异步方法存在阻塞的情况,又调用量大,注意有可能导致OOM(线程还未结束,又增加了更多的线程,最后导致内存溢出)。@Async注解可以选择使用自定义线程池。
它创建了SimpleAsyncTaskExecutor
说回RedisHttpSessionConfiguration,我们接着看:
@Bean public RedisMessageListenerContainer redisMessageListenerContainer() { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(this.redisConnectionFactory); if (this.redisTaskExecutor != null) { container.setTaskExecutor(this.redisTaskExecutor); } if (this.redisSubscriptionExecutor != null) { container.setSubscriptionExecutor(this.redisSubscriptionExecutor); } container.addMessageListener(this.sessionRepository(), Arrays.asList(new PatternTopic("__keyevent@*:del"), new PatternTopic("__keyevent@*:expired"))); container.addMessageListener(this.sessionRepository(), Collections.singletonList(new PatternTopic(this.sessionRepository().getSessionCreatedChannelPrefix() + "*"))); return container; } RedisMessageListenerContainer正是处理监听的类,RedisMessageListenerContainer设置了不为空的redisTaskExecutor,因为spring session默认没有配置该Executor,那RedisMessageListenerContainer在处理监听时怎么使用线程呢?我们接着看RedisMessageListenerContainer的源码: public void afterPropertiesSet() { if (this.taskExecutor == null) { this.manageExecutor = true; this.taskExecutor = this.createDefaultTaskExecutor(); } if (this.subscriptionExecutor == null) { this.subscriptionExecutor = this.taskExecutor; } this.initialized = true; } protected TaskExecutor createDefaultTaskExecutor() { String threadNamePrefix = this.beanName != null ? this.beanName + "-" : DEFAULT_THREAD_NAME_PREFIX; return new SimpleAsyncTaskExecutor(threadNamePrefix); }
afterPropertiesSet()这个方法熟悉吧,这个方法将在所有的属性被初始化后调用(InitializingBean接口细节这里不再赘述)。
所以如果用户没有定义springSessionRedisTaskExecutor,Spring session将调用createDefaultTaskExecutor()方法创建SimpleAsyncTaskExecutor线程池。而这个“线程池”处理任务时每次都创建新的线程。所以你会发现很多个redisMessageListenerContailner-X线程。
以上是“怎么解决Spring session监听导致创建大量redisMessageListenerContailner-X线程问题”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注创新互联行业资讯频道!