背景
在springboot项目中,接入了两个Redis。其中一个通过spring-data-redis接入,另一个是自己封装的redis,两个必须同时存在,不可删除任何一个。springboot的版本是1.5.9
这次的例子比较特殊,如果只是需要看JNI的对应表,请直接到:参考内容
小技巧
一般排查异常问题,直接找第一个“Caused by”后面的异常信息最后一个分号后面的内容即可。
异常信息如下:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webMvcRequestHandlerProvider' defined in URL [jar:file:/Users/edz/install/apache-tomcat-8.5.37/webapps/ROOT/WEB-INF/lib/springfox-spring-web-2.9.2.jar!/springfox/documentation/spring/web/plugins/WebMvcRequestHandlerProvider.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'endpointHandlerMapping' defined in class path resource [org/springframework/boot/actuate/autoconfigure/EndpointWebMvcManagementContextConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping]: Factory method 'endpointHandlerMapping' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mvcEndpoints' defined in class path resource [org/springframework/boot/actuate/autoconfigure/EndpointWebMvcManagementContextConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'environmentMvcEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/EndpointWebMvcManagementContextConfiguration.class]: Unsatisfied dependency expressed through method 'environmentMvcEndpoint' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration$$EnhancerBySpringCGLIB$$da7b48f9]: Constructor threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration$RedisHealthIndicatorConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisConnectionFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration$RedisConnectionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: redis.clients.jedis.JedisPool.<init>(Lorg/apache/commons/pool2/impl/GenericObjectPoolConfig;Ljava/lang/String;IILjava/lang/String;ILjava/lang/String;Z)V
不同纠结这段有多长,直接找最后一个分号后面的内容:
nested exception is java.lang.NoSuchMethodError: redis.clients.jedis.JedisPool.<init>(Lorg/apache/commons/pool2/impl/GenericObjectPoolConfig;Ljava/lang/String;IILjava/lang/String;ILjava/lang/String;Z)V
状况
项目启动到最后时,直接一句:Application startup failed,然后就是一段异常。o(≧口≦)o崩溃
解决过程
通过分析异常信息,可以得到具体的错误提示是:
redis.clients.jedis.JedisPool.<init>(Lorg/apache/commons/pool2/impl/GenericObjectPoolConfig;Ljava/lang/String;IILjava/lang/String;ILjava/lang/String;Z)V
现在定位到了异常,但是如果想要理解这种异常信息,就必须有简单的JNI基础:JedisPool.
但是仅仅知道这个还不够,因为这个类中充斥着大量的构造器,这种情况,就需要根据参数来确定具体是哪个构造器了
通过上面的构造器的参数转换出如下表:
标识 | 核心标识 | Java类型 |
---|---|---|
Lorg/apache/commons/pool2/impl/GenericObjectPoolConfig; | L | GenericObjectPoolConfig类 |
IILjava/lang/String; | I、I、L | 其实这是3个参数:int、int、String |
Z | Z | Boolean |
根据表格的信息发现,spring-data初始化redis时,没有使用redis官方的jar,而是使用了自己封装的redis。再一看自己封装的redis,其中竟然使用了和redis官方jar中同名的“redis.clients.jedis.JedisPool”(这中做法就不在此吐槽了。。。。)
然而这种骚操作直接导致了,spring-data在初始化redis时,懵逼了。。。。
为了保证两个redis可以同时使用,只能对spring-data-redis进行降级,保证即使使用自己封装的Redis也可以找到对应的构造器
参考内容
Java 类型 | 符号 |
---|---|
Boolean | Z |
Byte | B |
Char | C |
Short | S |
Int | I |
Long | J |
Float | F |
Double | D |
Void | V |
objects对象 | 以”L”开头,以”;”结尾,中间是用”/“ 隔开的包及类名。比如:Ljava/lang/String;如果是嵌套类,则用$来表示嵌套。例如 “(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z” |