这几天补充了下文档,这里接《Spring Cloud终篇 | 总结 一:一个完整的企业级SpringCloud架构(Mybatis--多数据源)》之后,简述一下Redis二级缓存及feign的调用方式。
源码案例:https://github.com/liujun19921020/SpringCloudDemo/blob/master/ProjectDemo/企业SpringCloud架构-xxljob-redis-elasticsearch
或 :链接:https://pan.baidu.com/s/1ooqaIRSeX6naOZ51aBWNHA 提取码:cwsw
这里是整了一个架构集合案例,其中的ES/xxl-job将在下两章讲解,该文主要源码为sc-muster-item-demo项目
案例中,在sc-muster-item-demo项目中调用sc-item-demo项目中的"/orderProduct/updateOrderStatus"接口(pom.xml引包、添加注解等详细操作步骤可回顾下《Spring Cloud教程 | 第四篇:服务消费者(Feign调用)》等)
在sc-muster-item-demo项目中配置调用sc-item-demo项目的FeignClient,这里把熔断类也加上了,实际使用中可根据情况看是否需要。
/**
* 调用sc-item-demo服务
*/
@FeignClient(name = "sc-item-demo",fallback = ScItemDemoFeignHystrix.class)
public interface ScItemDemoFeignClient {
/**
* 根据 订单号(批量)/商品sku 修改订单状态
* @param data
* @return
*/
@PostMapping("/orderProduct/updateOrderStatus")
ResponseMsg updateOrderStatus(@RequestBody JSONObject data);
}
/**
* 调用sc-item-demo服务熔断类
*/
@Component
public class ScItemDemoFeignHystrix implements ScItemDemoFeignClient {
@Override
public ResponseMsg updateOrderStatus(JSONObject data) {
return null;
}
}
然后我们通过Service调用对应的FeignClient方法即可,如下,
@Service
public class OrderAmazonDetailServiceImpl implements IOrderAmazonDetailService {
@Autowired
private ScItemDemoFeignClient scItemDemoFeignClient;
/**
* 根据 订单号/商品sku 批量修改订单状态(Feign方式调用)
* @param data
*/
@Override
public void updateOrderStatus(JSONObject data) throws Exception {
ResponseMsg responseMsg = scItemDemoFeignClient.updateOrderStatus(data);
if (null == responseMsg) {// 调用服务失败
throw new Exception("调用sc-item-demo服务失败");
}
if (responseMsg.getCode() != Code.SUCCESS) {// 调用服务报错
throw new Exception(responseMsg.getMsg());
}
//List
通过调用sc-muster-item-demo项目的接口可以看到调用成功,Controller我就不贴出来了
1、啥也不说,先配置数据源,没配置啥也不能干
#----------------------------------redis配置. 线上请用Redis Cluster---------------------------------------------
#spring.redis.cluster.nodes=39.108.60.150:7001,39.108.60.150:7002,119.23.237.229:7003,119.23.237.229:7004,120.77.157.244:7005,120.77.157.244:7006
spring.redis.host=192.168.71.146
spring.redis.port=23230
spring.redis.password=yibai_dev@redis
spring.redis.jedis.pool.max-active=1000
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=2
spring.redis.jedis.timeout=2000
2、先说说用Redis做二级缓存,需要实现Cache类。
/**
* 使用Redis来做Mybatis的二级缓存
* 实现Mybatis的Cache接口
*/
public class MybatisRedisCache implements Cache {
private static final Logger logger = LoggerFactory.getLogger(MybatisRedisCache.class);
// 读写锁
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
@Resource
private RedisTemplate redisTemplate;
private String id;
public MybatisRedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
logger.info("Redis Cache id " + id);
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public void putObject(Object key, Object value) {
logger.info("key==================>" + key);
if (value != null) {
// 向Redis中添加数据,有效时间是2天
redisTemplate.opsForValue().set(key.toString(), value, 2, TimeUnit.DAYS);
}
}
@Override
public Object getObject(Object key) {
try {
if (key != null) {
Object obj = redisTemplate.opsForValue().get(key.toString());
return obj;
}
} catch (Exception e) {
logger.error("redis ");
}
return null;
}
@Override
public Object removeObject(Object key) {
try {
if (key != null) {
redisTemplate.delete(key.toString());
}
} catch (Exception e) {
}
return null;
}
@Override
public void clear() {
logger.debug("清空缓存");
try {
Set keys = redisTemplate.keys("*:" + this.id + "*");
if (!CollectionUtils.isEmpty(keys)) {
redisTemplate.delete(keys);
}
} catch (Exception e) {
}
}
@Override
public int getSize() {
Long size = (Long) redisTemplate.execute(new RedisCallback() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.dbSize();
}
});
return size.intValue();
}
@Override
public ReadWriteLock getReadWriteLock() {
return this.readWriteLock;
}
}
然后配置中指明实现二级缓存的方式,我这里是放在application.yml中配置的:
spring.cache.type=REDIS
接下来就可以对你需要缓存的语句进行声明了,通过Mapper接口的方式是
@CacheNamespace(implementation=(com.xxx.xxx.MybatisRedisCache.class))
3、再说说Redis做变量存储吧
配置一个RedisConfig类,实现CachingConfigurerSupport,然后写个RedisTemplate的实现方式通过@Bean初始化到工厂吧(源码案例中实现的功能要多些,可以自己去看看)
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 重写Redis序列化方式,使用Json方式:
* 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。
* Spring Data JPA为我们提供了下面的Serializer:
* GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。
* 在此我们将自己配置RedisTemplate并定义Serializer。
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer
使用的时候,直接通过
redisTemplate.opsForValue().set(K var1, V var2);//写入
redisTemplate.opsForValue().get(K var1);//读出
例如:
@RestController
@RequestMapping("/redisDemo")
public class RedisDemoController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private RedisTemplate redisTemplate;
private static final String REDIS_DEMO_CALL = "REDIS_DEMO_CALL";
/**
* 根据条件查询订单详细信息列表(分页)
* @param data
* @return
*/
@PostMapping("/getRedisCall")
public ResponseMsg getRedisCall(@RequestBody JSONObject data){
try {
String nowDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));//当前时间
// 获取上次调用时间
Object callDateObj = redisTemplate.opsForValue().get(REDIS_DEMO_CALL);
String lastDateObj = callDateObj == null ? "未调用" : callDateObj.toString();
// 更新时间
redisTemplate.opsForValue().set(REDIS_DEMO_CALL, nowDate);
return new ResponseMsg(Code.SUCCESS, lastDateObj,"查询上次调用时间成功!");
} catch (Exception e) {
logger.error("查询上次调用时间失败!", e);
return new ResponseMsg<>(Code.FAIL, null, "查询上次调用时间失败==》" + e.getMessage());
}
}
}
调用2次的结果: