1. 程式人生 > >第三方介面呼叫案例(以阿里雲簡訊服務為例)

第三方介面呼叫案例(以阿里雲簡訊服務為例)

第三方介面或者服務大部分都是以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等分散式的開源框架。