# 165. 商品详情页动态渲染系统:依赖服务将数据变更消息写入 rabbitmq 或双写 redis

本次整合是在 eshop-product-service 项目中

# 整合 rabbitmq 的发送与消费

添加依赖

compile 'org.springframework.boot:spring-boot-starter-amqp'
1

自动配置

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: admin
    password: 123456  
1
2
3
4
5
6

此自动配置在 org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration.RabbitTemplateConfiguration#rabbitTemplate 中被应用,

# 生产者与消费者的 helloWord 代码如下

// 生产者
@Component  
public class RabbitMQSender {  

    @Autowired  
    private AmqpTemplate rabbitTemplate;  

    public void send(String message) {  
        this.rabbitTemplate.convertAndSend("my-queue", message);  
    }  

}  

// 消费者
@Component  
@RabbitListener(queues = "my-queue")  
public class RabbitMQReceiver {  

    @RabbitHandler  
    public void process(String message) {  
        System.out.println("从my-queue队列接收到一条消息:" + message);  
    }  

}  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 业务实现

商品服务数据变更,将消息写入 rabbitmq,时效性比较低的数据,走 rabbitmq,然后后面就接着整套动态渲染系统去玩儿

封装一个生产者

package cn.mrcode.cache.eshop.productserver.rabbitmq;

@Component
public class RabbitMQSender {
    @Autowired
//    private AmqpTemplate amqpTemplate;
    private RabbitTemplate rabbitTemplate;

    public void send(String queue, String message) {
        this.rabbitTemplate.convertAndSend(queue, message);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

在以下服务中添加事件发送

BrandService
CategoryService
ProductIntroService
ProductPropertyService
ProductService
ProductSpecificationService
1
2
3
4
5
6

先封装一个事件实体,服务中以该实体作为载体,比自己拼接 json 串方便

public class ProductEvent {
    private String eventType;
    private String dataType;
    private Long id;

    public ProductEvent(String eventType, String dataType, Long id) {
        this.eventType = eventType;
        this.dataType = dataType;
        this.id = id;
    }
}
1
2
3
4
5
6
7
8
9
10
11

这里以品牌为例:

@Service
public class BrandServiceImpl implements BrandService {

    @Autowired
    private BrandMapper brandMapper;
    @Autowired
    private RabbitMQSender rabbitMQSender;

    public void add(Brand brand) {
        brandMapper.add(brand);
        // data_change_queue 队列名称,不会自动创建,所以需要在 ui 中手动创建
        rabbitMQSender.send(RabbitMQName.DATA_CHANGE_QUEUE, JSON.toJSONString(new ProductEvent("add", "brand", brand.getId())));
    }

    public void update(Brand brand) {
        brandMapper.update(brand);
        rabbitMQSender.send(RabbitMQName.DATA_CHANGE_QUEUE, JSON.toJSONString(new ProductEvent("update", "brand", brand.getId())));
    }

    public void delete(Long id) {
        brandMapper.delete(id);
        rabbitMQSender.send(RabbitMQName.DATA_CHANGE_QUEUE, JSON.toJSONString(new ProductEvent("delete", "brand", id)));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 整合 redis

价格服务和库存服务数据变更,直接将数据双写到 redis 中, 时效性比较高的数据,直接 mysql+redis 双写,不走动态渲染系统,写到 redis 之后,后面走 OneService 服务提供页面的 ajax 调用

添加依赖

compile 'org.springframework.boot:spring-boot-starter-data-redis'
1

添加自动配置(有关 spring-boot-starter-data-redis (opens new window) 的详细深入配置请去官网查询)

spring:
  redis:
    port: 6379
    host: localhost
1
2
3
4

使用处直接使用 RedisTemplate 即可

@Autowired
private RedisTemplate<String, String> redisTemplate;
1
2

这里以商品价格服务来示例

@Autowired
private RedisTemplate<String, String> redisTemplate;

public void add(ProductPrice productPrice) {
    productPriceMapper.add(productPrice);
    redisTemplate.opsForValue().set("product_price_" + productPrice.getId(), JSON.toJSONString(productPrice));
}

public void update(ProductPrice productPrice) {
    productPriceMapper.update(productPrice);
    redisTemplate.opsForValue().set("product_price_" + productPrice.getId(), JSON.toJSONString(productPrice));
}

public void delete(Long id) {
    productPriceMapper.delete(id);
    redisTemplate.delete("product_price_" + id);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17