第三方接口或者服务大部分都是以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已省略)

@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等分布式的开源框架。