SpringBoot整合Redis环境并自己实现注解缓存

时间: 2023-08-02 admin 互联网

SpringBoot整合Redis环境并自己实现注解缓存

SpringBoot整合Redis环境并自己实现注解缓存

引入环境

<!--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;}@Autowiredprivate RedisConnectionFactory redisConnectionFactory;@Beanpublic CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)).cacheDefaults(redisCacheConfiguration).build();}@Beanpublic 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;@PostConstructprivate 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 {@Autowiredprivate 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

能力有限,有错误之处请指正!!!