引入环境
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
配置环境
这里是在Redis单机下多个数据库配置
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Value("${redis.database.cache}")
private int cacheDatabase;
@Value("${redis.database.cache2}")
private int cacheDatabase2;
@Value("${redis.host}")
private String host;
@Value("${redis.password}")
private String password;
@Value("${redis.port}")
private int port;
@Value("${redis.timeout}")
private int timeout;
@Value("${redis.pool.max-idle}")
private int maxIdle;
@Value("${redis.pool.min-idle}")
private int minIdle;
@Value("${redis.pool.max-wait}")
private long maxWait;
private Duration timeToLive = Duration.ZERO;
public void setTimeToLive(Duration timeToLive){
this.timeToLive = timeToLive;
}
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));
return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)).cacheDefaults(redisCacheConfiguration).build();
}
@Bean
public JedisPoolConfig getJedisPoolConfig(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setBlockWhenExhausted(true);
jedisPoolConfig.setTestOnBorrow(true);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setMaxWaitMillis(10000);
return jedisPoolConfig;
}
@Bean(name = "cacheRedisTemplate")
public RedisTemplate<String, Object> getCacheRedisTemplate(){
System.out.println(host);
System.out.println(port);
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setPoolConfig(getJedisPoolConfig());
jedisConnectionFactory.setDatabase(cacheDatabase);
jedisConnectionFactory.setHostName(host);
jedisConnectionFactory.setPassword(password);
jedisConnectionFactory.setPort(port);
jedisConnectionFactory.setTimeout(timeout);
jedisConnectionFactory.afterPropertiesSet();
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
template.setKeySerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean(name = "cacheRedisTemplate2")
public RedisTemplate<String, Object> getCacheRedisTemplate2(){
System.out.println(host);
System.out.println(port);
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setPoolConfig(getJedisPoolConfig());
jedisConnectionFactory.setDatabase(cacheDatabase2);
jedisConnectionFactory.setHostName(host);
jedisConnectionFactory.setPassword(password);
jedisConnectionFactory.setPort(port);
jedisConnectionFactory.setTimeout(timeout);
jedisConnectionFactory.afterPropertiesSet();
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
template.setKeySerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
参数就自己在配置文件中填写就可以了。
利用AOP机制,进行注解缓存
定义接口
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {
String cacheNames() default "";
String key() default "";
String cacheSource() default "null";
}
这里定义了缓存名,缓存key值和数据库源
实现环绕切面逻辑
@Aspect
@Component
public class RedisCacheable {
@Resource
@Qualifier("cacheRedisTemplate")
private RedisTemplate<String, Object> cacheRedisTemplate;
@Resource
@Qualifier("cacheRedisTemplate2")
private RedisTemplate<String, Object> cacheRedisTemplate2;
private Map<String, RedisTemplate<String, Object>> cacheMap = null;
@PostConstruct
private void initCache(){
cacheMap = new HashMap<>();
cacheMap.put("cacheRedisTemplate", cacheRedisTemplate);
cacheMap.put("cacheRedisTemplate2", cacheRedisTemplate2);
}
@Pointcut("@annotation(redisCache)")
public void pointCut(RedisCache redisCache){}
@Around("pointCut(redisCache)")
public Object around(ProceedingJoinPoint pjp, RedisCache redisCache) throws Throwable {
Object result = null;
String methodName = pjp.getSignature().getName();
try {
if (cacheMap.get(redisCache.cacheSource()).hasKey(redisCache.key())){
result = cacheMap.get(redisCache.cacheSource()).opsForValue().get(redisCache.key());
}else {
result = pjp.proceed();
ValueOperations<String, Object> operations = cacheMap.get(redisCache.cacheSource()).opsForValue();
operations.set(redisCache.key(), result);
cacheMap.get(redisCache.cacheSource()).opsForValue().set(redisCache.key(), result);
}
} catch (Throwable e) {
//异常通知
System.out.println("The method " + methodName + " occurs exception:" + e);
throw new RuntimeException(e);
}
//后置通知
System.out.println("The method " + methodName + " ends");
return result;
}
}
这里就是对两个Redis模板进行管理,根据cacheSource来动态切换数据源,提高可扩展性。
同理可以扩写清除缓存、更新缓存和实现其他淘汰策略等。
测试
service层
public interface CacheService {
String test(String id, String content);
String test2(String id, String content);
}
@Service
@CacheConfig(cacheManager = "")
public class CacheServiceImpl implements CacheService {
@Override
@RedisCache(cacheNames = "test", key = "11", cacheSource = "cacheRedisTemplate")
public String test(String id, String content) {
return content;
}
@Override
@RedisCache(cacheNames = "test", key = "11", cacheSource = "cacheRedisTemplate2")
public String test2(String id, String content) {
return content;
}
}
controller层
@RestController
@RequestMapping("/trace")
public class TraceController {
@Autowired
private CacheService cacheService;
@GetMapping("/1")
public String test(@RequestParam("id") String id, @RequestParam("content") String content){
return cacheService.test(id, content);
}
@GetMapping("/2")
public String test2(@RequestParam("id") String id, @RequestParam("content") String content){
return cacheService.test2(id, content);
}
}
用浏览器测试
确认Redis是空的
浏览器输入的接口是用Redis数据库0,key值11,内容是test_1
查看数据库,已经有了
浏览器输入的接口是用Redis数据库0,key值不变,内容是test_1_update,但是因为有缓存,所有还是出现了test_1
浏览器输入的接口是用Redis数据库1,key值11,内容是test_2
查看数据库,已经有了
浏览器输入的接口是用Redis数据库1,key值不变,内容是test_2_update,但是因为有缓存,所有还是出现了test_2
能力有限,有错误之处请指正!!!