Spring Cloud(7.3):配置Consumer Server
接下来我们创建一个消费者服务。消费者服务从生产者服务拿取商品-价格信息,并保存在Redis中。同时,接收消息队列中生产者服务的更新提示,如果某个商品-价格被修改,则删除Redis中的缓存数据,并重新从生产者服务中取。
配置pom.xml
首先,在pom.xml中添加spring-cloud-stream,spring-cloud-starter-stream-kafka,spring-data-redis及Redis的客户端jedis依赖。
<!-- Spring cloud: stream -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<!-- Spring cloud starter: kafka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
<!--Spring Data: Redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<!--Redis Client -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
配置通道(channel),绑定器(binder),接收器(sink)
public interface ProductPriceSource {
@Input("productPriceInput")
SubscribableChannel productPriceInput();
}
[注] 这里创建了一个叫“productPriceInput”的自定义接收通道,如果不使用自定义,可以直接使用org.springframework.cloud.stream.messaging.Sink接口及叫input的接收通道(下面的yml文件会讲如何配置)。
@Component
public class ProductPriceMessageReceiver { private static final Logger logger = LoggerFactory.getLogger(ProductPriceMessageReceiver.class); @Autowired
private ProductPriceRedisRepository productPriceRedisRepository; @StreamListener("productPriceInput")
public void receiveMessage(Long productId) { logger.info(String.format(">>>>> Received Kafka message productId=%s.", productId.toString()));
if (productPriceRedisRepository.contains(productId)) {
productPriceRedisRepository.delete(productId);
logger.info(
String.format(">>>>> Delete ProductPrice data productId=%s from cache.", productId.toString()));
} else {
logger.info(
String.format(">>>>> No ProductPrice data productId=%s in cache. Skip.", productId.toString()));
}
}
}
[注] 这里配置了一个接收器bean,当消息队列有消息时,接受该消息并清除相应product的缓存。
@SpringBootApplication
@EnableBinding({ ProductPriceSource.class })
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
[注] Application中加入@EnableBinding注解,并把定义好的发射通道(output)或接收通道(input)绑定到该服务中。可以绑定多个。
配置RedisRepository
这里我们额外用到了Redis,当我们引入jar包后,系统会自动给我们创建一个RedisTemplate<Object, Object>。我们可以用这个RedisTemplate来对Redis进行增删改查操作。
public interface RedisRepository<HK, HV> {
boolean contains(HK id);
HV find(HK id);
void save(HV value);
void delete(HK id);
}
@Repository
public class ProductPriceRedisRepository implements RedisRepository<Long, ProductPriceEntity> { private static final String HASH_NAME = "product_price"; /**
* 自动注入的Bean有:<br>
* RedisTemplate<Object, Object>(in RedisAutoConfiguration)<br>
* StringRedisTemplate(in RedisAutoConfiguration)<br>
* RedisConnectionFactory(JedisConnectionFactory)<br>
*
* 所以只能定义成RedisTemplate<Object, Object>的形式<br>
*/
@Autowired
private RedisTemplate<Object, Object> redisTemplate; private HashOperations<Object, Long, ProductPriceEntity> hashOperations; @PostConstruct
private void init() {
hashOperations = redisTemplate.opsForHash();
} /* (non-Javadoc)
* @see com.mytools.repository.RedisRepository#contains(java.lang.Object)
*/
@Override
public boolean contains(Long id) {
return hashOperations.keys(HASH_NAME).contains(id);
} /* (non-Javadoc)
* @see com.mytools.repository.RedisRepository#find(java.lang.Object)
*/
@Override
public ProductPriceEntity find(Long productId) {
return hashOperations.get(HASH_NAME, productId);
} /* (non-Javadoc)
* @see com.mytools.repository.RedisRepository#save(java.lang.Object)
*/
@Override
public void save(ProductPriceEntity entity) {
hashOperations.put(HASH_NAME, entity.getProductId(), entity); } /* (non-Javadoc)
* @see com.mytools.repository.RedisRepository#delete(java.lang.Object)
*/
@Override
public void delete(Long productId) {
hashOperations.delete(HASH_NAME, productId);
}
}
配置application.yml
spring:
# Stream/Kafka info
cloud:
stream:
bindings:
# input -> productPriceInput (自定义通道)
productPriceInput:
# 要读到消息的消息队列的名称
destination: productPriceTopic
# 发送和接收消息类型
content-type: application/json
# 消费者组:保证消息只会被一组服务实例处理一次
group: productPriceGroup
# 使用kafka作为消息总线
kafka:
binder:
# 运行着kafka服务器的网络地址
brokers: www.mtools.com
# Redis/pool info (RedisProperties)
redis:
database:
host: www.mytools.com
port:
password:
timeout:
jedis:
pool:
# 最大连接数,0为没有限制
max-active:
# 最大空闲连接,0为没有限制
max-idle:
#最大建立连接等待时间,如果超过此时间将接到异常,设为-1表示无限制
max-wait: -1
#最小空闲连接,0为没有限制
min-idle:
API及其他业务逻辑
@Controller
@RequestMapping("pp")
public class ProductPriceController { @Autowired
private ProductPriceServiceImpl productPriceService; @GetMapping(value = "find/productId/{productId}")
@ResponseBody
public ProductPriceEntity find(@PathVariable String productId) {
return productPriceService.find(Long.valueOf(productId));
}
}
[注] 这里创建了一个API,用于查询商品价格。
@Service
@Transactional
public class ProductPriceServiceImpl { private static final Logger logger = LoggerFactory.getLogger(ProductPriceServiceImpl.class); @Autowired
private ProductPriceRedisRepository productPriceRedisRepository; @Autowired
private LoadBalancerClient loadBalancer; public ProductPriceEntity find(Long productId) { ProductPriceEntity result = null; if (productPriceRedisRepository.contains(productId)) {
result = productPriceRedisRepository.find(productId);
logger.info(">>>>> Get data from cache. {}", result.toString());
return result;
} ServiceInstance instance = loadBalancer.choose("app-db");
String path = String.format("http://%s:%s/app-db/pp/find/productId/%s", instance.getHost(), instance.getPort(),
productId.toString());
logger.info(path); RestTemplate restTemplate = new RestTemplate();
ResponseEntity<ProductPriceEntity> response = restTemplate.exchange(path, HttpMethod.GET, null,
ProductPriceEntity.class);
result = response.getBody();
logger.info(">>>>> Get data from downstream. {}", result == null ? "null" : result.toString()); if (result != null) {
productPriceRedisRepository.save(result);
} return result;
}
}
[注] 具体逻辑如下:
(1)如果缓存中有该数据,则从缓存中获取数据。
(2)如果缓存中没有该数据,则调用生产者服务获取数据。拿到数据后再存入缓存中。
Spring Cloud(7.3):配置Consumer Server的更多相关文章
- Spring Cloud Config(配置中心)
每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 一.简介 Spring Cloud Config为分布式系统中的外部配置提供服务器和客 ...
- spring cloud config将配置存储在数据库中
Spring Cloud Config Server最常见是将配置文件放在本地或者远程Git仓库,放在本地是将将所有的配置文件统一写在Config Server工程目录下,如果需要修改配置,需要重启c ...
- 跟我学SpringCloud | 第六篇:Spring Cloud Config Github配置中心
SpringCloud系列教程 | 第六篇:Spring Cloud Config Github配置中心 Springboot: 2.1.6.RELEASE SpringCloud: Greenwic ...
- Spring Cloud Config 实现配置中心,看这一篇就够了
Spring Cloud Config 是 Spring Cloud 家族中最早的配置中心,虽然后来又发布了 Consul 可以代替配置中心功能,但是 Config 依然适用于 Spring Clou ...
- spring cloud 2.x版本 Eureka Server服务注册中心教程
本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 1.创建服务注册中心 1.1 新建Spring boot工程:eureka-server 1 ...
- Spring Cloud Config的配置中心获取不到最新配置信息的问题
Spring Cloud Config的配置中心获取不到最新配置信息的问题 http://blog.didispace.com/spring-cloud-tips-config-tmp-clear/
- Spring Cloud Feign 自定义配置(重试、拦截与错误码处理) 实践
Spring Cloud Feign 自定义配置(重试.拦截与错误码处理) 实践 目录 Spring Cloud Feign 自定义配置(重试.拦截与错误码处理) 实践 引子 FeignClient的 ...
- spring cloud Eureka client配置(consumer通过Eureka发起对provider的调用)
参考:http://www.ityouknow.com/springcloud/2017/05/12/eureka-provider-constomer.html springboot版本:2.0.3 ...
- 笔记:Spring Cloud Ribbon 客户端配置详解
自动化配置 由于 Ribbon 中定义的每一个接口都有多种不同的策略实现,同时这些接口之间又有一定的依赖关系,Spring Cloud Ribbon 中的自动化配置能够很方便的自动化构建接口的具体实现 ...
随机推荐
- Git----查看提交日志
Git log 只包括当前分支的commit. 截图示例: Git reflog 显示整个本地仓储的commit(所有branch,包括已撤销的commit) 截图示例: Git reflog --r ...
- Centos 拒绝ssh远程暴力破解方法
佳木斯SEO摘要 有一天突然收到一封邮件,邮件内容告知我的ECS服务器作为肉鸡在攻击别的机器,期初一想,一定是我机器的账号密码被泄露,或者是被人暴力破解,于是乎,我就查询了一下我机器的账号登录记录. ...
- [cf1140D. Minimum Triangulation][dp]
D. Minimum Triangulation time limit per test 2 seconds memory limit per test 256 megabytes input sta ...
- appium问题汇总(持续更新。。。)
WEBVIEW_unknown adb版本较低,adb 1.0.32版本不支持安卓8.x版本,更新adb版本后正常 Install homebrew ruby -e "$(curl -fsS ...
- 【素数判定/筛法进阶算法】-C++
今天我们来谈一谈素数的判定/筛法. 对于每一个OIer来说,在漫长的练习过程中,素数不可能不在我们的眼中出现,那么判定/筛素数也是每一个OIer应该掌握的操作,那么我们今天来分享几种从暴力到高效的判定 ...
- 010——C#选择文件路径
(一)具体教程查看:011——C#创建ECXEL文件(附教程) (二)代码:foldPath 就是获取到的文件路径 private void button1_Click(object sender, ...
- 洛谷 P2580 于是他错误的点名开始了 题解
每日一题 day10 打卡 Analysis trie树模板题,只需用到简单的插入和查询就好了 如果想要学trie树,见信息学奥赛一本通·提高篇P82 #include<iostream> ...
- mongodb 导入json文件遇到的坑
使用mongoimport命令导入外部json文件时,发现一直报错 报错结果如下: json数据格式完全正确如下: 经过再三确认格式最终找到解决方案,原来用cmd导入数据时json { }包含的数据 ...
- C#中的线程(一)入门 转载
文章系参考转载,英文原文网址请参考:http://www.albahari.com/threading/ 转载:http://www.cnblogs.com/miniwiki/archive/2010 ...
- TensorFlow(十八):从零开始训练图片分类模型
(一):进入GitHub下载模型-->下载地址 因为我们需要slim模块,所以将包中的slim文件夹复制出来使用. (1):在slim中新建images文件夹存放图片集 (2):新建model文 ...