微服务架构-利用Redis特性进行业务解耦
背景:
接着上篇文章来,上篇文章讲的是如何利用ApplicationContext的事件机制来达到业务解耦,而且这只能作用在单体应用中。在当下这么盛行的微服务架构中,想要再利用此方案做业务解耦是不可能的了,我们也提到,现在比较流行的解决方案是利用消息队列来完成,例如现在流行的RabbitMQ、RocketMQ、ActiveMQ,Kafka。
当然了,我们还可以利用Redis的队列来完成,也是完全没问题的。刚好我自己的阿里云装好了一个redis,我们就直接用Redis来解决吧。Redis提供了生产/消费模式和发布/订阅模式。这里提一下,生产消费模式适合那些一对一的,因为只能一个消费者去消费:例如用户注册了只发短信提示。而我们之前的例子是一对多的,即用户注册了需要发送短信和发送邮件,所以我们会用到发布订阅模式,只要订阅了某个频道,所有订阅者都能收到这频道的消息,然后来对此进行消费。那么开始吧~
说到微服务我们会想到Spring Cloud,可是我们现在是业务解耦,不需要服务之间直接的调用,所以我们直接只使用Spring Boot做微服务架构即可。简单分四大模块,用户模块(hyf-user)、短信模块(hyf-message)、邮件模块(hyf-mail)、公共类模块(hyf-encapsulation)。
开始:
1、项目结构如下图所示:
2、因为使用Redis,所以我们首先得引入Redis相关依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
3、并且在application.properties写上配置:
# redis服务端口
spring.redis.port=6379
# redis的服务地址
spring.redis.host=127.0.0.1
# 如果redis设置了密码这里也要配上
spring.redis.password=xxx
# 连接超时时间(毫秒)
spring.redis.timeout=10000
# Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
spring.redis.database=0
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0
4、发布信息:
用户Service直接调用默认的StringRedisTemplate去给指定的通道发布消息即可
/**
* @author Howinfun
* @desc 用户Service
* @date 2019/5/13
*/
@Service
@Slf4j
@AllArgsConstructor
public class UserService {
private StringRedisTemplate stringRedisTemplate;
/**
* 用户注册
* @param user
*/
public void registerUser(User user){
log.info("用户:"+user.getName()+"注册成功");
// 给redis的channel中发布消息
String userInfo = JSON.toJSONString(user);
stringRedisTemplate.convertAndSend(UserConstants.USER_REGISTER,userInfo);
}
}
5、订阅频道:
1、订阅稍微麻烦一点,首先抽象一个消费信息的接口:
public interface AbstractReceiver {
// 消费消息的方法
void receiveMessage(Object message);
}
2、然后发送短信需要创建一个类去实现此接口,然后在重写方法里头实现自己的业务逻辑(发送邮件的同理):
/**
* @author Howinfun
* @desc
* @date 2019/5/14
*/
@Component
public class MessageReceiver implements AbstractReceiver {
@Autowired
private MessageService messageService;
@Override
public void receiveMessage(Object message) {
User user = JSON.parseObject((String) message, User.class);
// 发送短信的业务逻辑
messageService.sendMessage(user);
}
}
3、然后需要给短信订阅弄一个配置类(发送邮件的同理):
/**
* @author Howinfun
* @desc
* @date 2019/5/14
*/
@Configuration
public class RedisConfig {
/**
* redis消息监听器容器
* 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
* @param messageListener
* @return
*/
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter messageListener) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
//mailListener订阅了一个叫user:register 的通道
container.addMessageListener(messageListener, new PatternTopic(UserConstants.USER_REGISTER));
return container;
}
/**
* 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法
* @param receiver
* @return
*/
@Bean
MessageListenerAdapter messageListener(MessageReceiver receiver) {
//这个地方 是给messageListenerAdapter 传入一个消息接受的处理器,利用反射的方法调用“receiveMessage”
//MessageListenerAdapter提供的默认调用处理器的方法是handleMessage 可以自己到源码里面看
// 所以如果我们定义的方法不是这个,需要在构造函数这添加上
return new MessageListenerAdapter(receiver, "receiveMessage");
}
}
6、最后我们就可以启动项目来测试一下了,可以看到已经成功了:
hyf-user控制台:
2019-05-15 09:55:16.493 INFO 13672 --- [nio-8080-exec-2] com.hyf.user.service.UserService : 用户:howinfun注册成功
2019-05-15 09:55:16.626 INFO 13672 --- [nio-8080-exec-2] io.lettuce.core.EpollProvider : Starting without optional epoll library
2019-05-15 09:55:16.627 INFO 13672 --- [nio-8080-exec-2] io.lettuce.core.KqueueProvider : Starting without optional kqueue library
hyf-message控制台:
2019-05-15 09:55:17.422 INFO 8088 --- [ container-2] com.hyf.message.service.MessageService : 给用户howinfun发送短信,手机号码为:12345678900
hyf-mail控制台:
2019-05-15 09:55:17.422 INFO 15352 --- [ container-2] com.hyf.mail.service.MailService : 给用户howinfun发送邮件,EMail为:baidu@qq.com
最后
因为不想篇幅太长,所以只放上了核心代码,需要详细了解的可到码云上看:Redis解决业务解耦源码
可能有些同学会问到,万一redis挂了呢,那就岂不是没得发动短信和发动邮件了?答案是对的~哈哈哈,挂了那当然就没得发送了。不过对于这种关联性不强的没啥所谓,注册完没法短信也不是特别大的事情,但是呢,如果是电商的项目,下单和减少库存可是要强一致性的,那么有啥方案,可参考https://mp.weixin.qq.com/s/FAlv-qE1jjiiF0JPoMVcWA?
微服务架构-利用Redis特性进行业务解耦的更多相关文章
- 微服务架构中的Redis
了解如何将Redis与Spring Cloud和Spring Data一起使用以提供配置服务器,消息代理和数据库. Redis可以广泛用于微服务架构中.它可能是少数流行的软件解决方案之一,你的应用程序 ...
- 一文读懂 Spring Boot、微服务架构和大数据治理三者之间的故事
微服务架构 微服务的诞生并非偶然,它是在互联网高速发展,技术日新月异的变化以及传统架构无法适应快速变化等多重因素的推动下诞生的产物.互联网时代的产品通常有两类特点:需求变化快和用户群体庞大,在这种情况 ...
- Spring Boot、微服务架构和大数据
一文读懂 Spring Boot.微服务架构和大数据治理三者之间的故事 https://www.cnblogs.com/ityouknow/p/9034377.html 微服务架构 微服务的诞生并非偶 ...
- Re:从 0 开始的微服务架构--(四)如何保障微服务架构下的数据一致性--转
原文地址:http://mp.weixin.qq.com/s/eXvoJew3bjFKzLLJpS0Otg 随着微服务架构的推广,越来越多的公司采用微服务架构来构建自己的业务平台.就像前边的文章说的, ...
- 【Spring Cloud】微服务架构选型方案
1.技术架构 2.组件介绍 1.服务注册与发现——Eureka 服务注册与发现中心采用Eureka,以AP为核心的高可用注册中心,保证高可用性和最终一致性,server之间互相注册的replicate ...
- 网易蜂巢微服务架构:用RabbitMQ实现轻量级通信
本次分享内容由三个部分组成: 微服务架构与MQ RabbitMQ场景分析与优化 RabbitMQ在网易蜂巢中的应用和案例分享 1微服务架构与MQ 微服务架构是一种架构模式,它将单体应用划分成一组微小的 ...
- 微服务架构基础之Service Mesh
ServiceMesh(服务网格) 概念在社区里头非常火,有人提出 2018 年是 ServiceMesh 年,还有人提出 ServiceMesh 是下一代的微服务架构基础. 那么到底什么是 Serv ...
- Scala微服务架构 一
因为公司的一个项目需求变动会非常频繁,同时改动在可控范围内,加上产品同学喜欢一些超前思维,我们的CTO决定提前开启八门,使用微服务架构. 划重点 微服务架构主要特点: ==独立组件(自主开发升级)== ...
- 浅谈微服务架构、容器技术与K8S
关注嘉为科技,获取运维新知 企业应用系统:从单体应用走向微服务架构:从裸金属走向容器. 如果在诸多热门云计算技术诸如容器.微服务.DevOps.OpenStack等之中,找出一个最火的方向,那么可能非 ...
随机推荐
- ACM-ICPC 2018 沈阳赛区(网络赛)
D.Made In Heaven One day in the jail, F·F invites Jolyne Kujo (JOJO in brief) to play tennis with he ...
- 牛客练习赛17 B-好位置
传送门 题意:本来惯例中文题不解释的, 但是有些人不懂这个题意, 简单的来说, 就是s1每一个的每一个字符都可以和别的字符构成一个子串 == s2. 算了还是惯例中文题意不解释吧. 题解:其实以前写 ...
- 【Offer】[15] 【二进制中1的个数】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 思路分析 让整数和1相与,可以判断整数二进制表示中最右边一位是否为1, ...
- idea中applicationContext-dao.xml文件中Cannot resolve file***** :spring xml model validation问题
访问不了classpath下的文件夹中的文件 解决办法如下:(问题出在我创建的resources文件夹是一个普通的文件夹) 1.本来是普通的文件夹 2.ctrl+shift+alt+s打开如下界面: ...
- 拒绝一次性买卖:MyBatis的mapper和repository可重复生成工具
背景 MyBatis的历史可谓久远了,码农们也在用着各式各样的代码生成工具.然而这些工具大部分都有一个缺点,那就是只能一次性生成文件.如果我们期间在生成的文件里做了修改,再次生成时,很多工具会覆盖我们 ...
- Java 创建/识别条形码、二维码
条形码(Barcode)是将宽度不等的多个黑条和空白,按照一定的编码规则排列,用以表达一组信息的图形标识符.常用于标示物品的生产国.制造厂家.商品名称.生产日期.图书分类号.邮件起止地点.类别.日期等 ...
- Hibernate,一对多,多对一
Hibernate环境的配置 hibernate.cfg.xml的配置 <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibern ...
- VS中一些提高编码效率的快捷键
场景 新手入门,看见大神们在VS中只用键盘就可以完成一系列操作. 整理一些常用的能提高效率的快捷键. 关注公众号霸道的程序猿获取编程相关电子书.教程推送与免费下载. 大量编程视频教程:https:// ...
- Webdriver元素定位的方法
webdriver提供了8种元素定位方法: 1.id 2.name 3.tag name 4.class name 5.link text 6.partial link text 7.xpath 8. ...
- 章节十六、10-TestNG报告和日志
一.在进行自动化的过程中,日志一般采用log4j 2进行日志记录,但TestNG自己本身也带有日志记录功能(reporter),它的好处在于日志中记录的内容都是testng自动生成的. package ...