# 175. 商品详情页动态渲染系统:基于 Spring Cloud 开发数据直连服务
前面多级缓存的核心思路是:如果 nginx local cache 没有,则通过 twemproxy 读本机房的从集群, 如果还是没有,则发送 http 请求给数据直连服务
那么这里数据直连的核心思路是:
- 先找本地 ehcache(前面讲解过,这里忽略不讲解),
- 如果没有,则走 redis 主集群,
- 如果还是没有,则通过 fegion 拉取依赖服务的接口
- 将数据写入主集群中,主集群会同步到各个机房的从集群
- 同时数据直连服务将获取到的数据返回给 nginx,nginx 会写入自己本地 local cache
服务实现,创建一个服务 eshop-datalink-service
application.yml
server:
port: 9110
logging:
level:
root: info
# 启动显示 controller 中的路径映射也就是 mapping
org.springframework.web: TRACE
spring:
application:
name: eshop-datalink-service
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
redis: # 这里连接的是 twemproxy 代理地址,主机群的
port: 1111
host: 192.168.99.11
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
核心就在这一个请求方法中
package cn.mrcode.cache.eshop.datalinkrserver.web.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.mrcode.cache.eshop.datalinkrserver.service.EshopProductService;
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private EshopProductService eshopProductService;
@RequestMapping("/{id}")
public String get(@PathVariable Long id) {
// 先从本地缓存获取,这里就不写了
// 再从 redis 主机群获取,获取逻辑参考数据聚合服务中的商品维度
Long productId = id;
String dimProductKey = "dim_product_" + productId;
String dimProductJsonStr = redisTemplate.opsForValue().get(dimProductKey);
// 如果商品聚合服务放入的 商品聚合信息没有在主机群查询到,那么就说明要么没有这个商品,要么就是过期了
if (StringUtils.isBlank(dimProductJsonStr)) {
// 需要访问原始服务之间获取数据,按照数据聚合服务的聚合逻辑聚合起来
String productJsonStr = eshopProductService.findProductById(productId);
if (StringUtils.isBlank(productJsonStr)) {
// 没有这个商品信息
return null;
}
// 否则继续获取其他维度数据
JSONObject product = JSON.parseObject(productJsonStr);
// 这里需要在商品服务中增加按 productId 查询的接口
String productPropertyJsonStr = eshopProductService.findProductPropertyByProductId(productId);
if (StringUtils.isNotBlank(productPropertyJsonStr)) {
product.put("productProperty", JSON.parseObject(productPropertyJsonStr));
}
String productSpecificationJsonStr = eshopProductService.findProductSpecificationByProductId(productId);
if (StringUtils.isNotBlank(productSpecificationJsonStr)) {
product.put("productSpecification", JSON.parseObject(productSpecificationJsonStr));
}
dimProductJsonStr = product.toJSONString();
redisTemplate.opsForValue().set(dimProductKey, dimProductJsonStr);
}
return dimProductJsonStr;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
下一章再测试,这里需要启动虚拟机中的 redis 集群,才能测试这个逻辑。