異常堆棧資訊 原文連結
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加載
- 然後我們就能注入啦