天天看點

spring+dubbo內建redis錯誤解決

異常堆棧資訊 原文連結

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisServiceImpl': Unsatisfied dependency expressed through field 'stringRedisTemplate'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.core.StringRedisTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:587)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:373)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1348)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:578)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:501)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:760)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
	at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:88)
	at com.yyl.BlogServiceStart.main(BlogServiceStart.java:18)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.core.StringRedisTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1509)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1065)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584)
	... 14 more
[INFO ] 2019-09-17 10:10:34,406(6072) --> [DubboShutdownHook] com.alibaba.dubbo.config.AbstractConfig$1.run(AbstractConfig.java:81): [INFO ] 2019-09-17 10:10:34,408(6074) --> [DubboShutdownHook] com.alibaba.dubbo.registry.support.AbstractRegistryFactory.destroyAll(AbstractRegistryFactory.java:64): Disconnected from the target VM, address: '127.0.0.1:65110', transport: 'socket'
           

異常原因分析

@Service
 public class RedisServiceImpl implements RedisService {
		@Autowired
		private StringRedisTemplate stringRedisTemplate;
		@Override
		public void set(String key, String value) {
				stringRedisTemplate.opsForValue().set(key, value);
		}

		@Override
		public String get(String key) {
				return stringRedisTemplate.opsForValue().get(key);    }

		@Override
		public boolean expire(String key, long expire) {
			return stringRedisTemplate.expire(key, expire, TimeUnit.SECONDS);
		}

		@Override
		public void remove(String key) {
			stringRedisTemplate.delete(key);
		}

		@Override
		public Long increment(String key, long delta) {
			return stringRedisTemplate.opsForValue().increment(key,delta);   
        }
 }
           

由代碼和異常堆棧資訊可知我想在service中注入一個stringRedisTemplate但是這個bean并沒有被spring管理到。是以我就看源碼查spring什麼情況下會加載這個bean。經查源碼發現:

@Configuration
@EnableDubbo(scanBasePackages = "com.yyl.service")
@ComponentScan("com.yyl")
@MapperScan("com.yyl.mapper")
@PropertySource(value = {"classpath:/dubbo.properties"})
//我的錯誤的原因就是沒有在我的配置檔案中開啟自動配置和開啟緩存。也就是下面的注解
 //@EnableAutoConfiguration
//@EnableCaching
           

剖析

  • spring會掃描@EnableAutoConfiguration這個注解。會加載spring-boot-autoconfigure這個jar包
  • 當掃描到@EnableCaching這個注解會通過spi加載spring.factories 的org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\這個類
  • RedisAutoConfiguration會加載application.properties

    spring.redis.database=0

    #redis伺服器名稱

    spring.redis.host=127.0.0.1

    #redis伺服器密碼

    #spring.redis.password=123456

    #redis伺服器連接配接端口号

    spring.redis.port=6379

    #redis連接配接池設定

    spring.redis.jedis.pool.max-idle=8

    spring.redis.jedis.pool.min-idle=0

    #spring.redis.sentinel.master=

    #spring.redis.sentinel.nodes=

    spring.redis.timeout=60000``

  • 接下來再看RedisAutoConfiguration這個類
@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class,JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
		public RedisAutoConfiguration() {
 }
@Bean
@ConditionalOnMissingBean(name = {"redisTemplate"})
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory          redisConnectionFactory)throws UnknownHostException {
					RedisTemplate<Object, Object> template = new RedisTemplate();
					template.setConnectionFactory(redisConnectionFactory);
					return template;
			}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory 
		        redisConnectionFactory) throwsUnknownHostException {
                 StringRedisTemplate template = new StringRedisTemplate();
                template.setConnectionFactory(redisConnectionFactory);
              return template;
		 	}
}
           
  • RedisProperties類會将application.properties這個redis相關的配置加載
  • 然後将StringRedisTemplate執行個體化被spirng加載
  • 然後我們就能注入啦