第三方介面呼叫案例(以阿里雲簡訊服務為例)
第三方介面或者服務大部分都是以rest風格的,需要http請求去呼叫,通過網路傳送請求去呼叫,然後等待第三方服務的響應,併發量多的話,會嚴重拖慢業務邏輯的處理速度。為了提高系統的效能,呼叫第三方服務,最好做成非同步的,如果條件允許,最好用單獨的伺服器,或者幾臺伺服器來做呼叫第三方介面,來提高業務邏輯的處理速度。當然,測試環境也可以用一臺機器來做偽分散式。
實現方式:將業務邏輯與呼叫第三方服務的程式碼分離,來達到解耦,以及非同步呼叫,具體實現(以呼叫阿里雲簡訊服務為例):
1、編寫配置類
public class ApiConfig implements Serializable {
private static final long serialVersionUID = -3043278191484112872L;
/**
* 產品名稱
*/
protected String product;
/**
* 介面域名或者IP地址
*/
protected String domain;
/**
* appCode;
*/
protected String accessKeyId;
/**
* appSecret
*/
protected String accessKeySecret;
/**
* 連結超時時間
*/
private String defaultConnectTimeout;
/**
* 讀取返回引數的超時時間
*/
private String defaultReadTimeout;
/**
* 簡訊模板程式碼
*/
private String templateCode;
/**
* 簽名
*/
private String signName;
/**
* 請求引數
*/
private String templateParam;
省略get,set方法
}
2、將呼叫阿里雲服務的demo封裝成介面:
public interface ShortMessageSendService<T extends ApiConfig> {
/**
* 傳送簡訊
* @param config 配置類(appkey等配置資訊)
* @param phoneNumbers 要傳送的手機號
* @param templateParam 簡訊的模板以及簡訊的內容
* @throws ClientException
*/
public void sendMsessages (T config, String phoneNumber, String templateParam,Emp user) throws ClientException;
/**
* 獲取資訊傳送結果
* @param config 配置類(appkey等配置資訊)
* @param ShortMessage 傳送的簡訊的內容,以及是否傳送成功
* @throws ClientException
* @throws ParseException
*/
public void getMessageInfo (T config, ShortMessage message) throws ClientException, ParseException;
}
2、根據業務邏輯,把不同型別的簡訊進行分類,並編寫配置檔案,方便spring自動注入。
mes.product = Dysmsapi
mes.domain = dysmsapi.aliyuncs.com
mes.accessKeyId =
mes.accessKeySecret =
mes.queueName =
mes.defaultConnectTimeout = 10000
mes.defaultReadTimeout = 10000
spring 配置父類:
<bean id="messageConfig" class="com.zedev.config.ApiConfig">
<property name="product" value="${mes.product}"></property>
<property name="domain" value="${mes.domain}"></property>
<property name="accessKeyId" value="${mes.accessKeyId}"></property>
<property name="accessKeySecret"
value="${mes.accessKeySecret}"></property>
<property name="defaultConnectTimeout"
value="${mes.defaultConnectTimeout}"></property>
<property name="defaultReadTimeout"
value="${mes.defaultReadTimeout}"></property>
<property name="queueName" value="${mes.queueName}"></property>
</bean>
spring 配置子類1:簡訊模板和簽名不一樣
<bean id="XXConfig"
class="com.zedev.config.XXConfig" parent="messageConfig">
<property name="templateCode" value="${vio.mes.templateCode}"></property>
<property name="signName" value="${vio.mes.signName}"></property>
</bean>
spring 配置子類2:簡訊模板和簽名不一樣
<bean id="XXXConfig"
class="com.zedev.config.XXXConfig" parent="messageConfig">
<property name="templateCode"
value="${code.mes.templateCode}"></property>
<property name="signName" value="${code.mes.signName}"></property>
</bean>
3、結合訊息佇列,將呼叫簡訊介面和業務邏輯進行解耦。
將簡訊息傳送給訊息佇列:(訊息佇列的配置jmsQueueTemplate已省略,原始碼: https://github.com/jialestudio/lib)
@Component
public class MessageSender {
@Autowired
@Qualifier("jmsQueueTemplate")
private JmsTemplate jmsTemplate;
/**
* @Description: 將訊息傳送給訊息佇列
* @param destination 訊息佇列名稱
* @param message 訊息體
*/
public void send(String destination, final String message) {
jmsTemplate.send(destination, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
return jmsTemplate.getMessageConverter().toMessage(message, session);
}
});
}
}
訊息佇列監聽器:
@Component
@EnableJms
public class MesSenderQueueListener {
protected Logger log = LoggerFactory.getLogger(ViolationQueryQueueListener.class);
// 當收到訊息後,自動呼叫該方法,spring配置預設監聽器,負責接收訊息 concurrency = "3-8"最少三個執行緒,最多8個執行緒監聽,啟用多執行緒,提高系統效率
@JmsListener(containerFactory = "jmsListenerContainerFactory", destination = "訊息佇列名", concurrency = "3-8")
public void onMessage(Message message) throws JMSException {
ActiveMQTextMessage msg = (ActiveMQTextMessage) message;
final String ms = msg.getText();
try {
if (StringUtils.isBlank(ms)) {
return;
}
Emp user = null;
user = userService.getSystemUser();
/**
* 業務邏輯處理,呼叫2傳送請求,並獲取資訊傳送的結果,並存入資料庫
*/
XXConfig= null;
param = JSONObject.parseObject(ms, XXConfig.class);// 轉換成相應的物件
if (null == param) {
return;
}
//這裡呼叫呼叫簡訊傳送的介面,生成記錄簡訊的物件ShortMessage ,並存入資料庫中。
} catch (Exception e) {
log.info(ms);
e.printStackTrace();
}
}
}
阿里雲簡訊回執訊息佇列監聽器
@Component
public class ShortMessageQueueListener {
@Autowired
private VioMessageConfig cioConfig;
@Autowired
private ShortMessageService mesService;
private Logger log = LoggerFactory.getLogger(ShortMessageQueueListener.class);
@PostConstruct
public void listenMessage() throws ClientException, ParseException {
DefaultAlicomMessagePuller puller = new DefaultAlicomMessagePuller();
puller.startReceiveMsg(cioConfig.getAccessKeyId(), cioConfig.getAccessKeySecret(), "SmsReport",
cioConfig.getQueueName(), new MyMessageListener());
}
class MyMessageListener implements MessageListener {
@Override
public boolean dealMessage(Message message) {
JSONObject result = null;
result = JSONObject.parseObject(message.getMessageBodyAsString());
if (null == result) {
return true;
}
//業務邏輯,更新MesSenderQueueListener生成的傳送結果,並處理相關的業務邏輯
}
}
}
以上可以整合到一個系統,也可以整合成分散式架構,不需要spring cloud或者dubbo等分散式的開源框架。