Open
pinyht
opened this issue 2 years ago
•
20 comments
When I use Jedis 4.0.0 in Springboot, it can't start, in jedis 3.7.1 is OK
Redis / Jedis Configuration
there is my config file
@Configuration
@Slf4j
public class RedisConfig {
@Value("${spring.redis.host:}")
private String host;
@Value("${spring.redis.port:0}")
private int port;
@Value("${spring.redis.password:}")
private String password;
@Value("${spring.redis.database:0}")
private int database;
@Value("${spring.redis.jedis.pool.max-active:0}")
private int maxActive;
@Value("${spring.redis.jedis.pool.max-idle:0}")
private int maxIdle;
@Value("${spring.redis.timeout:0}")
private int timeout;
@Bean
public JedisPool jedisPool() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxActive);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWait(Duration.ofMillis(timeout));
JedisPool pool = new JedisPool(jedisPoolConfig, host, port, timeout, password, database);
return pool;
}
}
error log
org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [JedisPool [maxTotal=100, blockWhenExhausted=true, maxWaitDuration=PT20S, lifo=true, fairness=false, testOnCreate=false, testOnBorrow=false, testOnReturn=false, testWhileIdle=true, durationBetweenEvictionRuns=PT30S, numTestsPerEvictionRun=-1, minEvictableIdleTimeDuration=PT1M, softMinEvictableIdleTimeDuration=PT-0.001S, evictionPolicy=org.apache.commons.pool2.impl.DefaultEvictionPolicy@11c7a0b4, closeLock=java.lang.Object@75ed125a, closed=false, evictionLock=java.lang.Object@653a5967, evictor=org.apache.commons.pool2.impl.BaseGenericObjectPool$Evictor@5a85b4e6, evictionIterator=null, factoryClassLoader=java.lang.ref.WeakReference@766b6d02, oname=org.apache.commons.pool2:type=GenericObjectPool,name=pool, creationStackTrace=java.lang.Exception
at org.apache.commons.pool2.impl.BaseGenericObjectPool.(BaseGenericObjectPool.java:407)
at org.apache.commons.pool2.impl.GenericObjectPool.(GenericObjectPool.java:147)
at redis.clients.jedis.util.Pool.(Pool.java:16)
at redis.clients.jedis.util.Pool.(Pool.java:12)
at redis.clients.jedis.JedisPool.(JedisPool.java:359)
at redis.clients.jedis.JedisPool.(JedisPool.java:278)
at redis.clients.jedis.JedisPool.(JedisPool.java:188)
at redis.clients.jedis.JedisPool.(JedisPool.java:160)
at com.eashung.xiaodu.infrastructure.redis.config.RedisConfig.jedisPool(RedisConfig.java:72)
at com.eashung.xiaodu.infrastructure.redis.config.RedisConfig$$EnhancerBySpringCGLIB$$5519e373.CGLIB$jedisPool$0()
at com.eashung.xiaodu.infrastructure.redis.config.RedisConfig$$EnhancerBySpringCGLIB$$5519e373$$FastClassBySpringCGLIB$$bab84c1c.invoke()
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
at com.eashung.xiaodu.infrastructure.redis.config.RedisConfig$$EnhancerBySpringCGLIB$$5519e373.jedisPool()
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:486)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1389)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:656)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:302)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290)
at com.eashung.xiaodu.application.chat.ApplicationChatApplication.main(ApplicationChatApplication.java:15)
, borrowedCount=0, returnedCount=0, createdCount=0, destroyedCount=0, destroyedByEvictorCount=0, destroyedByBorrowValidationCount=0, activeTimes=StatsStore [[]], size=100, index=0], idleTimes=StatsStore [[]], size=100, index=0], waitTimes=StatsStore [[]], size=100, index=0], maxBorrowWaitDuration=PT0S, swallowedExceptionListener=null, factoryType=null, maxIdle=10, minIdle=0, factory=redis.clients.jedis.JedisFactory@6b09ce57, allObjects={}, createCount=0, idleObjects=[], abandonedConfig=null]] with key 'jedisPool'; nested exception is javax.management.InstanceAlreadyExistsException: MXBean already registered with name org.apache.commons.pool2:type=GenericObjectPool,name=pool
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:626) ~[spring-context-5.3.14.jar:5.3.14]
at org.springframework.jmx.export.MBeanExporter.lambda$registerBeans$2(MBeanExporter.java:552) ~[spring-context-5.3.14.jar:5.3.14]
at java.base/java.util.HashMap.forEach(HashMap.java:1336) ~[na:na]
at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:552) ~[spring-context-5.3.14.jar:5.3.14]
at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:435) ~[spring-context-5.3.14.jar:5.3.14]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:972) ~[spring-beans-5.3.14.jar:5.3.14]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.14.jar:5.3.14]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.14.jar:5.3.14]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.2.jar:2.6.2]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[spring-boot-2.6.2.jar:2.6.2]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412) ~[spring-boot-2.6.2.jar:2.6.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:302) ~[spring-boot-2.6.2.jar:2.6.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.2.jar:2.6.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290) ~[spring-boot-2.6.2.jar:2.6.2]
at com.eashung.xiaodu.application.chat.ApplicationChatApplication.main(ApplicationChatApplication.java:15) ~[classes/:na]
Caused by: javax.management.InstanceAlreadyExistsException: MXBean already registered with name org.apache.commons.pool2:type=GenericObjectPool,name=pool
at java.management/com.sun.jmx.mbeanserver.MXBeanLookup.addReference(MXBeanLookup.java:151) ~[na:na]
at java.management/com.sun.jmx.mbeanserver.MXBeanSupport.register(MXBeanSupport.java:160) ~[na:na]
at java.management/com.sun.jmx.mbeanserver.MBeanSupport.preRegister2(MBeanSupport.java:173) ~[na:na]
at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:919) ~[na:na]
at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:890) ~[na:na]
at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:320) ~[na:na]
at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522) ~[na:na]
at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:138) ~[spring-context-5.3.14.jar:5.3.14]
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:672) ~[spring-context-5.3.14.jar:5.3.14]
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:616) ~[spring-context-5.3.14.jar:5.3.14]
... 14 common frames omitted
@pinyht Please check javax.management.InstanceAlreadyExistsException: MXBean already registered with name org.apache.commons.pool2:type=GenericObjectPool,name=pool
I have try to use "jedisPoolConfig.setJmxNamePrefix("jedis")" ,but it can't start too, the log changes to:
javax.management.InstanceAlreadyExistsException: MXBean already registered with name org.apache.commons.pool2:type=GenericObjectPool,name=jedis
@pinyht Can you set a breakpoint in org.apache.commons.pool2.impl.BaseGenericObjectPool#jmxRegister? And debug to see if there will be two calls to here? If so, what is their stack?
Will you initialize two JedisPool objects, otherwise jmxRegister will not be called twice
I noticed that the variable registered is true for the second time, and i = 1. This is a bit confusing to me, because when i = 1, registered should be false
@yangbodong22011 no,I just have one config,can you test in same jedis version and springboot version? when I used jedis 3.7.1,it's OK with the same config file
@zeekling yes, I have read this article,but disable jmx is not a normal choice, I think jedis 4.0.0 have some bug, because I used jedis 3.7.1 with same springboot version and same config class, it can be started normal
I get the same spring exception. For now I will keep on using Jedis 3.7.1 because that doesn't have the issue indeed. Would be nice if this could be fixed in a future version!
I get the same spring exception. For now I will keep on using Jedis 3.7.1 because that doesn't have the issue indeed. Would be nice if this could be fixed in a future version!
Hey @zeekling, there is no specific code failing. It is a compile error right. But it seems to have something to do with incompatibility with spring-data.
I don't really have time for full minimal example, but for me the registration happened in two places due to spring mbean autodetection mechanism:
Spring does it in org.springframework.jmx.export.MBeanExporter#registerBeans (using org.springframework.jmx.support.JmxUtils#isMBean for detecting candidates)
Jedis does it in constructor of JedisPool through BaseGenericObjectPool.
Solutions I see:
disable jmx in JedisPoolConfig and let bean be registered by spring.
JedisPoolConfig config = new JedisPoolConfig();
config.setJmxEnabled(false)
...
exclude bean from MBeanExporter and stick to constructor registration. For example:
As @el-dot said ( https://github.com/redis/jedis/issues/2781#issuecomment-1032632503 ):
If you register JedisPoolConfig or some other class extends BaseGenericObjectPool or it's subclass GenericObjectPoolConfig ( which in apache commons pool ) instances to spring . this problem will happen 。becase the same instance registered to jmx twice .
And you can use "config.setJmxEnabled(false)' to stop GenericObjectPoolConfig to register to jmx , and then only spring will register this bean to jmx .you can find the registered jmx bean though jmc (locate in jdk).
you can see invoke logic in those class:
MBeanExporter class in spring-context-{version}.jar
public static boolean isMXBeanInterface(Class<?> interfaceClass) {
if (!interfaceClass.isInterface())
return false;
if (!Modifier.isPublic(interfaceClass.getModifiers()) &&
!Introspector.ALLOW_NONPUBLIC_MBEAN) {
return false;
}
MXBean a = interfaceClass.getAnnotation(MXBean.class);
if (a != null)
return a.value();
return interfaceClass.getName().endsWith("MXBean");
// We don't bother excluding the case where the name is
// exactly the string "MXBean" since that would mean there
// was no package name, which is pretty unlikely in practice.
}
Yeah . Actually the "return interfaceClass.getName().endsWith("MXBean");“ logic works when use apache commons pool .