待解决的问题
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.redisSub ionExecutor != null) {
container.setSub ionExecutor(this.redisSub ionExecutor);
}
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.sub ionExecutor == null) {
this.sub ionExecutor = 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线程。
继续阅读与本文标签相同的文章
-
将阿里云产品整合成为高校课程实训的训练营产品的实践(四)
2026-05-18栏目: 教程
-
中间人攻击,HTTPS也可以被碾压
2026-05-18栏目: 教程
-
什么叫做IaC,与DevOps有什么关系?如何实现?
2026-05-18栏目: 教程
-
解读《运维知识体系》,直面自动化运维的“灵魂八问”
2026-05-18栏目: 教程
-
阿里99大促 | 模型识别背后的样本生成
2026-05-18栏目: 教程
