Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

希望支持 Jedis 3.x #1647

Closed
prosaically opened this issue Jun 28, 2020 · 7 comments
Closed

希望支持 Jedis 3.x #1647

prosaically opened this issue Jun 28, 2020 · 7 comments

Comments

@prosaically
Copy link

prosaically commented Jun 28, 2020

希望能够支持Jedis 3.x。

个人建议

ConfigStorage Jedis的实现构造应该统一使用WxRedisOps来构造,因为不使用统一会出现以下问题。

版本编号

  1. WxJava 3.8.0
  2. Jedis 3.2.0
  3. spring-boot-starter-data-redis 2.3

问题体现

异常环境

  1. Java JDK 1.8.0_201
  2. centos-release-7-6.1810.2.el7.centos.x86_64

环境差异

windows 10,jdk 1.8.0_171 下能正常运行。

代码实现

    @Bean
    public WxMpService wxMpService(StringRedisTemplate redis, WeChatConfig cfg) {
        RedisTemplateWxRedisOps ops = new RedisTemplateWxRedisOps(redis);
        WxMpRedisConfigImpl config = new WxMpRedisConfigImpl(ops, "wx");
        config.setAppId(cfg.getAppId());
        config.setSecret(cfg.getSecret());
        config.setToken(cfg.getToken());
        config.setAesKey(cfg.getEncodingAesKey());
        WxMpService wxService = new WxMpServiceImpl();
        wxService.setWxMpConfigStorage(config);
        return wxService;
    }

异常日志

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'wechatController': Unsatisfied dependency expressed through field 'wxMpServiceMap'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'wxMpService' defined in class path resource [com/egu365/api/config/WebConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [me.chanjar.weixin.mp.api.WxMpService]: Factory method 'wxMpService' threw exception; nested exception is java.lang.NoClassDefFoundError: redis/clients/util/Pool
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:895)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
	at com.egu365.api.Egu365RestApiApplication.main(Egu365RestApiApplication.java:19)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:109)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
	at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'wxMpService' defined in class path resource [com/egu365/api/config/WebConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [me.chanjar.weixin.mp.api.WxMpService]: Factory method 'wxMpService' threw exception; nested exception is java.lang.NoClassDefFoundError: redis/clients/util/Pool
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:656)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:636)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1524)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1488)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1407)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1264)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1226)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
	... 28 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [me.chanjar.weixin.mp.api.WxMpService]: Factory method 'wxMpService' threw exception; nested exception is java.lang.NoClassDefFoundError: redis/clients/util/Pool
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651)
	... 44 common frames omitted
Caused by: java.lang.NoClassDefFoundError: redis/clients/util/Pool
	at com.egu365.api.config.WebConfig.wxMpService(WebConfig.java:212)
	at com.egu365.api.config.WebConfig$$EnhancerBySpringCGLIB$$14eddc6.CGLIB$wxMpService$22(<generated>)
	at com.egu365.api.config.WebConfig$$EnhancerBySpringCGLIB$$14eddc6$$FastClassBySpringCGLIB$$3f0fb69c.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
	at com.egu365.api.config.WebConfig$$EnhancerBySpringCGLIB$$14eddc6.wxMpService(<generated>)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
	... 45 common frames omitted
Caused by: java.lang.ClassNotFoundException: redis.clients.util.Pool
	at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:129)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 56 common frames omitted

原因分析

使用Spring Data Redis,本生的目的是屏蔽Jedis客户端复杂和版本差异。

RedisTemplateWxRedisOps ops = new RedisTemplateWxRedisOps(template);

使用RedisTemplateWxRedisOps时,只要SpringDataRedis能正常运行,WxMpRedisConfigImpl也应该能正常运行。

  • 但由于windows 和linux下的jdk对class加载方式有差异。
 // 编号1
 // 未使用的构造
  public WxMpRedisConfigImpl(JedisPool jedisPool) {
    this(new JedisWxRedisOps(jedisPool), "wx");
  }
 // 编号2
 // 使用的构造器
  public WxMpRedisConfigImpl(WxRedisOps redisOps, String keyPrefix) {
    this.redisOps = redisOps;
    this.keyPrefix = keyPrefix;
  }

理论上来说,使用2号构造器,应该能正常使用,但是在Linux环境,Jdk确会加载1号构造器的依赖关系。
如果移除1号构造号,统一WxRedisOps来构造,就可以避免这样的问题。
WxMpRedisConfigImpl和JedisWxRedisOps(JedisPool jedisPool)没有直接依赖关系。也就不会去加载redis.clients.util.Pool。

  • 这样能够统一依赖,降压依赖的复杂程度。
  • 能够更加灵活,如果有特殊实现,也只需关注WxRedisOps接口。

_ 以上仅个人建议,希望项目越来越完善,成代码中最靓的仔 _

@xuxinlong001
Copy link

spring-boot-starter-data-redis 已经默认支持lettuce,不支持jedis,所以一直报错,建议3.8版本去除对jedis的依赖

@binarywang
Copy link
Member

感谢楼主建议,本来SDK只关注微信相关接口实现,最初是没有引入redis相关依赖的,但后期为了满足大家需求,引入了相关实现,也仅是作为参考。
如果大家有更好的实现,欢迎随时提供PR。

@gyjx
Copy link

gyjx commented Jul 2, 2020

嗯 这就解决了我,为什么windows下启动没错,linux启动报错的问题!谢谢

@binarywang
Copy link
Member

#1605 跟此问题中提到的方法类似,准备去掉第一个构造方法

@binarywang
Copy link
Member

请使用最新测试版本看是否还有问题

@prosaically
Copy link
Author

weixin-java-miniapp 的 config WxMaRedisBetterConfigImpl 也需要调整

public WxMaRedisBetterConfigImpl(JedisPool jedisPool) {
    this(new JedisWxRedisOps(jedisPool), "wa");
}

@binarywang
Copy link
Member

binarywang commented Jul 6, 2020

weixin-java-miniapp 的 config WxMaRedisBetterConfigImpl 也需要调整

public WxMaRedisBetterConfigImpl(JedisPool jedisPool) {
    this(new JedisWxRedisOps(jedisPool), "wa");
}

建议可以自己先在本地测试,没问题后直接提交PR,这样会比较高效些

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants