问题描述:
SpringBoot + 虚拟机redis
context with path [] threw exception [Request processing failed; nested exception is redis.clients.jedis.exceptions.JedisExhaustedPoolException: Could not get a resource since the pool is exhausted] with root cause
java.util.NoSuchElementException: Timeout waiting for idle object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:444) ~[commons-pool2-2.8.0.jar:2.8.0]
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:354) ~[commons-pool2-2.8.0.jar:2.8.0]
at redis.clients.jedis.util.Pool.getResource(Pool.java:50) ~[jedis-3.3.0.jar:na]
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:288) ~[jedis-3.3.0.jar:na]
at com.example.demo.redis.RedisService.get(RedisService.java:20) ~[classes/:na]
at com.example.demo.controller.HelloController.redisGet(DemoController.java:69) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_251]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_251]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_251]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_251]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.36.jar:9.0.36]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) [tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) [tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.36.jar:9.0.36]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_251]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_251]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.36.jar:9.0.36]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_251]
原始代码:
spring.redis.port=6379
# Redis服务器连接密码
spring.redis.password=123456
# 连接超时时间(毫秒)
spring.redis.timeout=20000
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=5
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=5
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=3
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=5
package com.example.demo.redis;
import com.alibaba.fastjson.JSON;
import org.apache.ibatis.annotations.Insert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@Service
public class RedisService {
@Autowired
private JedisPool jedisPool;
public T get(String key,Classclazz){
Jedis jedis = null;
try{
jedis = jedisPool.getResource();
String str = jedis.get(key);
T t = sringtoBean(str,clazz);
return t;
}finally {
returnToPool(jedis);
}
}
private T sringtoBean(String str,Class clazz) {
if(str == null|| str.length() <= 0||clazz == null) return null;
if(clazz == int.class ||clazz == Integer.class){
return (T) Integer.valueOf(str);
}else if(clazz == String.class){
return (T)str;
}else if(clazz == long.class || clazz == Long.class){
return (T)Long.valueOf(str);
}else {
return JSON.toJavaObject(JSON.parseObject(str),clazz);
}
//还没有加list的方法
}
public boolean exists(String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.exists(key);
} finally {
returnToPool(jedis);
}
}
public boolean set(String key,T value){
//JedisPool jp = null;
Jedis jedis = null;
try{
jedis = jedisPool.getResource();
String str = beanToString(value);
jedis.set(key,str);
return true;
}finally {
returnToPool(jedis);
}
}
private void returnToPool(Jedis jedis) {
if(jedis != null){
jedis.close();
}
}
private String beanToString(T value) {
if(value == null) return null;
Class> clazz = value.getClass();
if(clazz == int.class ||clazz == Integer.class){
return ""+value;
}else if(clazz == String.class){
return (String) value;
}else if(clazz == long.class || clazz == Long.class){
return ""+value;
}else {
return JSON.toJSONString(value);
}
}
}
package com.example.demo.redis;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Component
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
public class RedisConfig {
//@Value("${spring.redis.host}")
private String host;
//@Value("${spring.redis.port}")
private int port;
// @Value("${spring.redis.timeout}")
private int timeout;
//@Value("${spring.redis.password}")
private String password;
//@Value("${spring.redis.pool.max-active}")
private int poolMaxTotal;
// @Value("${spring.redis.pool.min-idle}")
// private int poolminIdle;
//@Value("${spring.redis.pool.max-idle}")
private int poolMaxIdle;
//@Value("${spring.redis.pool.max-wait}")
private int poolMaxWait;
public void setHost(String host) {
this.host = host;
}
public void setPort(int port) {
this.port = port;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public void setPassword(String password) {
this.password = password;
}
public void setPoolMaxTotal(int poolMaxTotal) {
this.poolMaxTotal = poolMaxTotal;
}
public void setPoolMaxIdle(int poolMaxIdle) {
this.poolMaxIdle = poolMaxIdle;
}
public void setPoolMaxWait(int poolMaxWait) {
this.poolMaxWait = poolMaxWait;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public int getTimeout() {
return timeout;
}
public String getPassword() {
return password;
}
public int getPoolMaxTotal() {
return poolMaxTotal;
}
public int getPoolMaxIdle() {
return poolMaxIdle;
}
public int getPoolMaxWait() {
return poolMaxWait;
}
}
package com.example.demo.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Service
public class RedisFactory {
@Autowired
RedisConfig redisConfig;
@Bean
public JedisPool JedisFactory(){
JedisPoolConfig poolConfig = new JedisPoolConfig();
// poolConfig.setMaxTotal(60);
// poolConfig.setMaxIdle(60);
// poolConfig.setMinIdle(60);
// poolConfig.setNumTestsPerEvictionRun(1024);
// poolConfig.setTimeBetweenEvictionRunsMillis(30000);
// poolConfig.setMinEvictableIdleTimeMillis(1800000);
// poolConfig.setSoftMinEvictableIdleTimeMillis(1800000);
// poolConfig.setMaxWaitMillis(500);
// poolConfig.setTestOnBorrow(false);
// poolConfig.setTestWhileIdle(true);
// poolConfig.setBlockWhenExhausted(false);
// JedisPool jp = new JedisPool(poolConfig,"192.168.0.123",6379,20000,"123456",0);
// return jp;
// JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000);
return new JedisPool(poolConfig,redisConfig.getHost(),redisConfig.getPort(),redisConfig.getTimeout(),redisConfig.getPassword(),0,false);
// poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
// poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
// poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait());
// poolConfig.setTestOnBorrow(false);
// JedisPool jp = new JedisPool(poolConfig,"192.168.0.103",6379,20000,"123456",0);
// return jp;
}
}
DemoController中
@Autowired
RedisService redisService;
@RequestMapping("/redis/get")
@ResponseBody
public Result redisGet(){
Object op = redisService.get("k1",Object.class);
return Result.success((String)op);
尝试方法:使用StringRedisTemplate template代替连接池,成功。说明配置文件没有写错。
错误出现在代码 jedis = jedisPool.getResource();提示说为null,最后意识到配置文件中少写了一个参数max-total
ps:没写这个的原因是以为max-total和max-active一样的,只是版本改了改名成了max-active,然鹅发现是我天真了,注意2020年的redIs 默认是spring.redis.XXX,当时以为是配置信息写错了一直将reids.XXX和spring.redis.XXX之间改来改去,其实是不需要修改的,它可以自动识别(就像jdbc一样)。另外因为spring.redis.XXX是原因还修改
@ConfigurationProperties(prefix = "spring.redis")原先是
@ConfigurationProperties(prefix = "redis")
spring.redis.pool-max-total=10
最一开始报错发现有root cause的信息,以为是防火墙的问题,然鹅虚拟机上没有安装防火墙,虚拟机上对所有主机6379端口开放,用telnet可以连接,Idea中StringRedisTemplate template()中也可以成功
还尝试了使用@value注解,无用(因为最关键的maxTotal没有写 )。最终效果