@Configuration
public class RedisConfig {
@Bean
public CachingConfigurerSupport keyGenerator() {
return new MyCachingConfigurerSupport();
}
public class MyCachingConfigurerSupport extends CachingConfigurerSupport {
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}
//缓存管理器
@SuppressWarnings("rawtypes")
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
//设置缓存过期时间
rcm.setDefaultExpiration(300);//秒
return rcm;
}
/**
* 存入对象tostring后的信息
*/
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的key也采用String的序列化方式,需要配置一下StringSerializer,不然key会乱码 /XX/XX
template.setHashKeySerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
// /**
// * 存入对象序列化信息
// *
// * @return
// */
// @Bean
// public RedisTemplate<String, Object> redisSerizlizerObj1() {
// RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// redisTemplate.setConnectionFactory(jedisConnectionFactory());
// // key采用String的序列化方式
// redisTemplate.setKeySerializer(new StringRedisSerializer());
// // value序列化方式采用jackson
// redisTemplate.setValueSerializer(new RedisObjectSerializer());
//
// // hash的key也采用String的序列化方式
// redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// // hash的value序列化方式采用jackson
// redisTemplate.setHashValueSerializer(new RedisObjectSerializer());
// return redisTemplate;
// }
@Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setPassword("jihy");
return jedisConnectionFactory;
}
}
@Configuration注解未生效,@Bean无法注入。
这个配置类和别的配置类没有任何区别,@Configuration和@Bean注解都有,无论怎么启动就是注入不进项目中,后来试着将该配置类先移动到其他(可以注入其他配置类的)包中,启动服务发现可以被扫描到。然后再将该配置类拖回原来的包中再重新启动服务,发现也可以了。没想明白为什么,这里记录一下。
看这个方法
修改了RedisTemplate
的默认序列化方式,默认序列化方式是JdkSerializationRedisSerializer
,这里改成Jackson2JsonRedisSerializer
序列化方式,可以序列化object对象为json字符串。
/**
* 存入对象tostring后的信息
*/
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的key也采用String的序列化方式,需要配置一下StringSerializer,不然key会乱码 /XX/XX
template.setHashKeySerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
修改完序列化方式之后,control中还需要使用该类RedisTemplate
,通过@Autowired private RedisTemplate template;
注入,启动项目报错了。
报错信息如下:
image.pngConsider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
意思是两个bean不知道注入哪一个,需要给其中一个更高的优先级。那为什么会出现这种情况呢?
首先需要了解Spring装配bean组件的三种方式:
- 隐式的Bean发现机制和自动装配
- 在Java中进行装配
- 在XML中进行装配
值得一提的是,我们在项目中应该优先实用隐式的Bean发现机制和自动装配,其次使用在Java中进行装配,最后再使用在XML中进行装配。
对于本项目
使用了 @Configuration+@Bean的基于Java的Bean装配 RedisTemplate类,
然后在control类中又通过@Autowired 隐式的Bean发现机制和自动装配 RedisTemplate类
两种方式导致框架不知道使用哪一个
所以有两种解决方法:
- 使用@Primary注解(该注解不能修饰属性)
正确的
image.png错误的
image.png- 配置类中注入的该类的方法名作为属性名
该方法名为 redisTemplate(),RedisTemplate类在项目中的 组件ID 与该方法名同名,在control中private RedisTemplate redisTemplate;
也使用改名作为属性,经过测试也是可以的。
测试方法是:System.out.println(redisTemplate.getValueSerializer());
查看打印出来的序列化方式是什么,默认序列化方式是JdkSerializationRedisSerializer
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的key也采用String的序列化方式,需要配置一下StringSerializer,不然key会乱码 /XX/XX
template.setHashKeySerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
Spring容器装配Bean的三种方式
隐式的Bean发现机制和自动装配
Spring从两个角度来实现自动化装配;组件扫描(Spring自动发现应用中上下文所需要的创建的Bean),自动装配(Spring自动满足Bean之间的依赖)
使用@Component将普通Java类配置成SpringBean
使用@Autowired(自动装配)使Spring满足Bean的依赖
@Component
public class User {
@Autowired
private Article article;
public void action() {
article.action();
}
}
基于Java的Bean装配
使用 @Bean 注解将方法返回的实例对象添加到上下文中
在@Bean返回的实例对象中可以通过构造器注入传入相关依赖
@Configuration
@ComponentScan("com.jimisun")
public class WebConfig {
@Bean
public User user() {
return new User(myArticle());
}
@Bean
public MyArticle myArticle() {
return new MyArticle();
}
}
基于XML的Bean装配
对于在XML中进行配置可能使我们经常使用的,在以前的Spring版本中几乎我们都是使用XML进行配置Spring,下面我们简单来看一下。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean class="com.jimisun.spring.example.User" id="user">
<constructor-arg ref="myArticle"/>
</bean>
<bean class="com.jimisun.spring.example.MyArticle" id="myArticle"></bean>
</beans>
注意:在实际应用中如何不想被海量的<bean>标签埋没前,你应当优先使用隐式的Bean发现机制和自动装配和在Java中进行装配,最后再选择使用在XML中配置。
最后值得一提的是在实际项目中我们通常都会选择组合使用
隐式的Bean发现机制和Java中进行装配进行组合
隐式的Bean发现机制和XML配置进行组合
网友评论