微服務架構-利用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?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM