循環依賴分爲2類:spring
Dubbo缺省會在啓動時檢查依賴的服務是否可用,不可用時會拋出異常,防止Spring初始化完成。這種狀況咱們就叫作RPC服務間循環依賴。出現了循環依賴,必須有一方先啓動。因此這種問題是必定須要解決的。app
應用間循環依賴大體狀況以下: A應用調用B應用的服務,B應用也會調用A應用的服務,不管是間接調用仍是直接調用。 這種循環依賴剛開始不會出現問題 ,但隨着代碼變動,有可能會發展爲RPC服務間循環依賴。運維
能夠經過check=」false」關閉檢查來避免 Dubbo的循環依賴的報錯,可是我認爲這個只是權益之計。dom
當前咱們應用中並無出現RPC服務間循環調用,可是出現了應用間循環調用。下面就是這個🌰就是這種狀況,我簡單描述下大體的狀況。ide
上面這個例子是應用間循環依賴,一不當心可能寫出暴雷的代碼。這裏應該儘快把這個坑填掉。post
針對應用間循環依賴,大體的解決辦法ui
團隊協做模式:阿里雲
通訊集成模式:code
因爲上述的2個服務早已開發完畢,且比較成熟的應用,並且直接的依賴仍是比較少的。此時MQ看起來是一個比較好的方案了。orm
這裏考慮到site-base
比marketing-base
是更加基礎的服務,因此圖一中上邊的調用流程不變,下方更改成site-base
發送消息,而後marketing-base
來消費消息的方式。如圖二所示。
首先,咱們須要向運維或者本身在單機環境下,新建立一個Topic。我這裏新建立一個名叫: newcar_siteinit_basicinfo_test 的主題。
在config/user/beans中添加一個spring xml 配置文件 application-mq.xml。
1 <!--ons config--> 2 <bean id="producerConfig" class="com.souche.optimus.mq.aliyunons.ONSProducerConnConfig"> 3 <property name="accessKey" value="${ons.access.key}"/> 4 <property name="secretKey" value="${ons.secret.key}"/> 5 </bean> 6 7 <!-- 集團初始化 發送者 --> 8 <bean id="groupInitProducerInvoker" class="com.souche.optimus.mq.aliyunons.ONSProducerInvoker"> 9 <property name="producerId" value="${ons.groupinit.producer.id}"/> 10 <property name="config" ref="producerConfig"/> 11 </bean> 12 13 <bean id="groupInitProducer" class="com.souche.optimus.mq.aliyunons.ONSProducer"> 14 <property name="topic" value="${ons.groupinit.topic}"/> 15 <property name="invoker" ref="groupInitProducerInvoker"/> 16 </bean>
增長ons.properties 在config/optimus/properties文件夾下
1ons.access.key = K8pfCPRU6gL2lldi 2ons.secret.key = U3lYVGl3L9nb23cEMogWcUVziLJ2T7 3 4#初始化主題 5ons.groupinit.topic = newcar_siteinit_basicinfo_test 6ons.groupinit.producer.id = PID_newcar_siteinit_basicinfo_test
1private void sendMsg(SiteGroupInfoDO siteGroupInfoDO) { 2 if (siteGroupInfoDO.getId() == null) { 3 return; 4 } 5 Map<String, Object> map = new HashMap<>(); 6 map.put("id",siteGroupInfoDO.getId()); 7 map.put("groupCode",siteGroupInfoDO.getGroupCode()); 8 map.put("groupName",siteGroupInfoDO.getGroupName()); 9 map.put("appName",siteGroupInfoDO.getAppName()); 10 map.put("domainSuffix",siteGroupInfoDO.getDomainSuffix()); 11 String uuid = UUIDUtil.getID(); 12 mqProducer.send(map, uuid, CommonConstant.MQ_TAG); 13 LOGGER.info("發送消息:body: {}, keys: {}, tag: {}", map, uuid, CommonConstant.MQ_TAG); 14 }
1 <bean id="contentPlatformMsgConsumer" class="com.souche.marketing.base.biz.mq.ContentPlatformMsgConsumer"/> 2 <bean id="tgcArticleInvoker" class="com.souche.optimus.mq.aliyunons.ONSConsumerInvoker"> 3 <property name="config" ref="consumerConfig"/> 4 <property name="reciver" ref="contentPlatformMsgConsumer"/> 5 <property name="consumerId" value="${mq.ons.consumer.newcar.article.id}"/> 6 <property name="topic" value="${mq.ons.consumer.newcar.article.topic}"/> 7 <!--<property name="tag" value="${mq.aliyun.car.center.tag}"/> <!–tag選填, 若是不填將監聽該topic下的全部消息–>--> 8 <property name="enabled" value="true"/> 9 </bean>
這裏有一個很重要的點是,咱們的消費者ID必須從阿里雲控制檯上創建或者聯繫運維建立,圖示以下:
1ons.access.key = K8pfCPRU6gL2lldi 2ons.secret.key = U3lYVGl3L9nb23cEMogWcUVziLJ2T7 3 4#初始化主題 5mq.ons.consumer.newcar.siteinit.topic = newcar_siteinit_basicinfo_test 6mq.ons.consumer.newcar.siteinit.id = GID_newcar_siteinit_basicinfo_test
1/** 2 * @author james mu 3 * @date 2019/11/7 10:16 4 */ 5public class GroupInitMsgConsumer implements MQConsumer { 6 7 public static final Logger LOGGER = LoggerFactory.getLogger(GroupInitMsgConsumer.class); 8 9 @Resource(name = "articleServiceForManageProvider") 10 private ArticleServiceForManage articleServiceForManage; 11 12 @Resource(name = "posterServiceForAppProvider") 13 private PosterServiceForApp posterServiceForApp; 14 15 @Override 16 public ConsumeResult onRecived(Map<String, Object> map) { 17 if (CollectionUtils.isEmpty(map)) { 18 LOGGER.warn("msg is empty"); 19 return ConsumeResult.CommitMessage; 20 } 21 JSONObject msg = new JSONObject(map); 22 Integer groupId = msg.getInteger("id"); 23 String groupCode = msg.getString("groupCode"); 24 String groupName = msg.getString("groupName"); 25 String appName = msg.getString("appName"); 26 String domainSuffix = msg.getString("domainSuffix"); 27 LOGGER.info("groupId: {}, groupCode: {}, groupName: {}, appName: {}, domainSuffix: {}", groupId, groupCode, groupName, appName, domainSuffix); 28 29 if (groupId == null) { 30 LOGGER.warn("param is miss"); 31 return ConsumeResult.CommitMessage; 32 } else { 33 articleServiceForManage.importSubjectForGroup(groupId); 34 SiteGroupInfoDTO siteGroupInfoDTO = new SiteGroupInfoDTO(); 35 siteGroupInfoDTO.setId(groupId); 36 siteGroupInfoDTO.setGroupCode(groupCode); 37 siteGroupInfoDTO.setGroupName(groupName); 38 siteGroupInfoDTO.setAppName(appName); 39 siteGroupInfoDTO.setDomainSuffix(domainSuffix); 40 posterServiceForApp.initPosterByGroup(siteGroupInfoDTO); 41 } 42 return ConsumeResult.CommitMessage; 43 } 44 45}
在消費消息的業務代碼中,你們必定要注意處理冪等性的問題,防止屢次消費消息,致使業務的出錯。在此,相信你們已經瞭解怎麼清除循環依賴的思路和處理了。