【发布时间】:2019-03-24 07:45:01
【问题描述】:
我需要更改 Redis 代码,以便它可以与新的 SpringBoot 2.0.3 一起使用,目前在启动 Tomcat 9.0.12 时(不作为 Jar 启动 SpringBoot - 业务需求的原因)我收到以下错误:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method vehicleHistoryCacheManager in somePath.config.UfCacheConfig
required a bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory' that could not be found.
- Bean method 'redisConnectionFactory' in 'JedisConnectionConfiguration' not loaded because @ConditionalOnMissingBean
(types: org.springframework.data.redis.connection.RedisConnectionFactory; SearchStrategy: all)
beans of type 'org.springframework.data.redis.connection.RedisConnectionFactory' redisConnectionFactory
- Bean method 'redisConnectionFactory' in 'LettuceConnectionConfiguration' not loaded because @ConditionalOnMissingBean
(types: org.springframework.data.redis.connection.RedisConnectionFactory; SearchStrategy: all)
found beans of type 'org.springframework.data.redis.connection.RedisConnectionFactory' redisConnectionFactory
Action:
Consider revisiting the conditions above or defining a bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory' in your configuration.
19-Oct-2018 13:43:22.142 SEVERE [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.ContainerBase.addChildInternal ContainerBase.addChild: start:
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/motoPolicy]]
(...)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'technicalController'
defined in file [somePath\TecController.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'ufCacheServiceImpl'
defined in URL [jar:file:/someName.jar!/somePath/UfCacheServiceImpl.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'vehicleHistoryCacheManager' defined in class path resource
[somePath/config/UfCacheConfig.class]:
Unsatisfied dependency expressed through method 'vehicleHistoryCacheManager' parameter 0;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=vehicleTemplate)}
(...)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ufgCacheServiceImpl'
defined in URL [jar:file:/uf.jar!/somePath/UfgCacheServiceImpl.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'vehicleHistoryCacheManager' defined in class path resource
[somePath/config/UfCacheConfig.class]:
Unsatisfied dependency expressed through method 'vehicleHistoryCacheManager' parameter 0;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=vehicleTemplate)}
(...)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'vehicleHistoryCacheManager' defined in class path resource
[somePath/config/UfCacheConfig.class]:
Unsatisfied dependency expressed through method 'vehicleHistoryCacheManager' parameter 0;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=vehicleTemplate)}
(...)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=vehicleTemplate)}
(...)
19-Oct-2018 13:43:22.162 SEVERE [RMI TCP Connection(3)-127.0.0.1] org.apache.tomcat.util.modeler.BaseModelMBean.invoke Exception invoking method manageApp
java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException:
Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/motoPolicy]]
(...)
[2018-10-19 01:43:22,176] Artifact motoPolicy-web:war exploded: Error during artifact deployment. See server log for details.
(...)
19-Oct-2018 13:43:22.162 SEVERE [RMI TCP Connection(3)-127.0.0.1] org.apache.tomcat.util.modeler.BaseModelMBean.invoke Exception invoking method createStandardContext
javax.management.RuntimeOperationsException: Exception invoking method manageApp
(...)
Caused by: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException:
Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/motoPolicy]]
(...)
我在 pom 中对 Redis 的依赖是:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.0</version>
</dependency>
这里是 redis 配置:
@Configuration
class RedisConfig {
@Value("${ufg.redis.host}") // 127.0.0.1
private String hostName;
@Value("${ufg.redis.port}") // 6379
private int port;
@Bean
LettuceConnectionFactory redisConnectionFactory() {
LettuceConnectionFactory redisConnectionFactory = new LettuceConnectionFactory();
redisConnectionFactory.setHostName(hostName);
redisConnectionFactory.setPort(port);
return redisConnectionFactory;
}
@Bean
ObjectMapper redisObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.registerModule(new Jdk8Module());
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+1:00"));
objectMapper.setDateFormat(new ISO8601DateFormat());
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return objectMapper;
}
}
这里是配置类:
@Slf4j
@Configuration
@EnableCaching
public class UfCacheConfig {
public static final String VEHICLE_HISTORY_CACHE_MANAGER = "vehicleHistoryCacheManager";
public static final String VEHICLE_HISTORY_CACHE = "vehicleHistoryCache";
public static final String VEHICLE_GENERATOR_NAME = "vehicleKeyGenerator";
public static final String PERSON_HISTORY_CACHE_MANAGER = "personHistoryCacheManager";
public static final String PERSON_HISTORY_CACHE = "personHistoryCache";
public static final String PERSON_GENERATOR_NAME = "personKeyGenerator";
@Value("${ufg.cache.expiration.validity.minutes}")
private int expirationValidityMinutes;
@Bean(value ="vehicleTemplate")
public RedisTemplate<String, GetVehicleInsuranceHistoryResponse> vehicleTemplate(RedisConnectionFactory redisConnectionFactory,
@Qualifier("redisObjectMapper") ObjectMapper objectMapper) {
RedisTemplate<String, GetVehicleInsuranceHistoryResponse> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
@Primary
@Bean(name = VEHICLE_HISTORY_CACHE_MANAGER)
public CacheManager vehicleHistoryCacheManager(@Qualifier("vehicleTemplate") RedisConnectionFactory redisConnectionFactory) {
Duration expiration = Duration.ofSeconds(expirationValidityMinutes * 60);
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(expiration)).build();
}
@Bean(value ="personTemplate")
public RedisTemplate<String, GetPersonInsuranceHistoryResponse> redisTemplate(RedisConnectionFactory redisConnectionFactory,
@Qualifier("redisObjectMapper") ObjectMapper objectMapper) {
RedisTemplate<String, GetPersonInsuranceHistoryResponse> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
@Bean(name = PERSON_HISTORY_CACHE_MANAGER)
public CacheManager personHistoryCacheManager(@Qualifier("personTemplate") RedisConnectionFactory redisConnectionFactory) {
Duration expiration = Duration.ofSeconds(expirationValidityMinutes * 60);
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(expiration)).build();
}
@Bean(name = VEHICLE_GENERATOR_NAME)
public KeyGenerator vehicleKeyGenerator() {
return (o, method, objects) -> new VehicleKeyGenerator((GetVehicleInsuranceHistoryRequest) objects[0]).generate();
}
@Bean(name = PERSON_GENERATOR_NAME)
public KeyGenerator personKeyGenerator() {
return (o, method, objects) -> new PersonKeyGenerator((GetPersonInsuranceHistoryRequest) objects[0]).generate();
}
private static <T> RedisTemplate<String, T> createTemplate(Class<T> clazz, RedisConnectionFactory redisConnectionFactory, ObjectMapper objectMapper) {
RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
Jackson2JsonRedisSerializer<T> serializer = new Jackson2JsonRedisSerializer<>(clazz);
serializer.setObjectMapper(objectMapper);
redisTemplate.setValueSerializer(serializer);
return redisTemplate;
}
}
这是堆栈跟踪中提到的服务类:
@Slf4j
@Service
public class UfCacheServiceImpl implements UfCacheService {
private CacheManager vehicleCacheManager;
private CacheManager personCacheManager;
@Autowired
public UfCacheServiceImpl(@Qualifier(VEHICLE_HISTORY_CACHE_MANAGER) CacheManager vehicleCacheManager,
@Qualifier(PERSON_HISTORY_CACHE_MANAGER) CacheManager personCacheManager) {
this.vehicleCacheManager = vehicleCacheManager;
this.personCacheManager = personCacheManager;
}
@Override
public void clear() {
log.info("Clearing ufg cache");
vehicleCacheManager.getCache(VEHICLE_HISTORY_CACHE).clear();
personCacheManager.getCache(PERSON_HISTORY_CACHE).clear();
}
}
如您所见,我使用了类似但 redis 不起作用的东西:
@Bean(value ="vehicleTemplate")
@Qualifier("vehicleTemplate")
编辑:
关于Boris 回复:
我可以找到(在整个项目中)带有jedis 或Jedis 之类的短语的唯一东西是 pom 依赖项。当我删除它们时,输出变为:
Parameter 0 of method vehicleHistoryCacheManager in somePackages.config.UfCacheConfig required a bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory' that could not be found.
- Bean method 'redisConnectionFactory' not loaded because @ConditionalOnClass did not find required class 'redis.clients.jedis.Jedis'
- Bean method 'redisConnectionFactory' in 'LettuceConnectionConfiguration' not loaded because @ConditionalOnMissingBean (types: org.springframework.data.redis.connection.RedisConnectionFactory;
SearchStrategy: all) found beans of type 'org.springframework.data.redis.connection.RedisConnectionFactory' redisConnectionFactory
我找不到像JedisConnectionConfiguration 这样的东西来删除它。
在 pom 中注释了依赖项后,我在外部库中找不到短语 jedis。
我在External Libraries 中看到带有spring-boot-starter-parent(在主父pom 中)的版本,我只有spring-data-redis 2.0.8。
【问题讨论】:
-
例如,当指定
<version>2.0.3.RELEASE</version>时,您将覆盖 DependencyManagement 中定义的版本。删除显式版本声明。 -
@Boris 有时我必须定义版本,因为我在 tomcat 中遇到错误。当我从这四个依赖项中删除版本时,我得到了同样的错误。我还看到我有两个版本的
spring-data-redis(在External Libraries)一个是2.0.8,第二个是1.8.14。 -
@Boris 现在当我尝试执行
mvn clean install时出现以下错误:[ERROR] 'dependencies.dependency.version' for io.lettuce:lettuce-core:jar is missing. @ line 161, column 21删除所有version不好。 -
这意味着您的 POM 文件缺少允许从 Spring Boot 继承默认值的
spring-boot-starter-parent<parent>块。您可以仔细检查并更新 POM sn-p 吗?有关详细信息,请参阅here。 -
引自Spring Boot in Action book, p.37:“......在覆盖由 Spring Boot 启动器依赖项传递引入的依赖项时要小心。虽然不同的版本可能工作正常,但有一个很棒的知道启动器选择的版本已经过测试可以很好地协同工作,您可以放心。您应该只在特殊情况下覆盖这些传递依赖项(例如较新版本中的错误修复)。"
标签: java spring spring-boot tomcat redis