dubbo实现动态调用

在支付网关的业务中,在用户支付成功/失败后需要异步通知业务方,这个时候业务方是一个变数,支付网关可以定义一个interface,各个业务方来实现这个接口。

支付网关配置一个回调配置表,表中包含:group、ZK的注册地址等dubbo调用必须要的参数值。

dubbo在ZK上的注册信息示例:

dubbo://192.168.18.234:20883/com.wy.payment.service.CutPaymentService?anyhost=true&application=installment&default.timeout=30000&dubbo=2.5.3&interface=com.wy.payment.service.CutPaymentService&methods=updateRepaymentPlan,updatePaymentOrderStatus,selectOrderByCondition,createRepaymentPlan,selectPayWaterByBid,cutPayment&pid=31913&revision=0.0.1-SNAPSHOT&side=provider&timestamp=1489374649211

 

动手开干,先建配置表。

 1 CREATE TABLE `pay_callback_config` (
 2   `id` bigint(20) NOT NULL AUTO_INCREMENT,
 3   `system_id` varchar(20) DEFAULT NULL COMMENT '业务系统标识',
 4   `registry_address` varchar(100) DEFAULT NULL COMMENT 'zk注册地址',
 5   `registry_group` varchar(50) DEFAULT NULL COMMENT 'zk注册组',
 6   `registry_version` varchar(20) DEFAULT NULL COMMENT '服务的版本号',
 7   `valid_flag` tinyint(1) DEFAULT '1' COMMENT '是否有效,1有效 0无效',
 8   `create_date` datetime DEFAULT NULL COMMENT '创建时间',
 9   PRIMARY KEY (`id`)
10 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='支付回调的配置表';

对应的domain类:

 1 package xxx.domain;
 2 
 3 import java.io.Serializable;
 4 import java.util.Date;
 5 
 6 import xxx.PaymentConstants;
 7 
 8 import lombok.Data;
 9 
10 /**
11  * 支付回调的相关配置 对应表:pay_callback_config
12  * 
13  * @author yangzhilong
14  *
15  */
16 @Data
17 public class PayCallbackConfig implements Serializable{
18     /**
19      * 
20      */
21     private static final long serialVersionUID = 339298526553679045L;
22     
23     private Long id;
24     /**
25      * 业务系统标识 {@link PaymentConstants.BUSINESS_SYSTEM}
26      */
27     private String systemId;
28     /**
29      * zk注册地址
30      */
31     private String registryAddress;
32     /**
33      * zk注册组
34      */
35     private String registryGroup;
36     /**
37      * 服务的版本号
38      */
39     private String registryVersion;
40     /**
41      * 有效标识
42      */
43     private Boolean validFlag;
44     /**
45      * 创建时间
46      */
47     private Date createDate; 
48 }

Spring Boot的配置类:

 1 package xx.configuration;
 2 
 3 import java.util.List;
 4 
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 7 import org.springframework.context.annotation.Bean;
 8 import org.springframework.context.annotation.Configuration;
 9 
10 import xx.domain.PayCallbackConfig;
11 import xx.mapper.PayCallbackConfigMapper;
12 import xx.utils.PayCallbackUtils;
13 import xx.utils.UselessBean;
14 
15 /**
16  * 支付回调的初始化代码
17  * 
18  * @author yangzhilong
19  *
20  */
21 @Configuration
22 @ConditionalOnClass(PayCallbackConfigMapper.class)
23 public class PayCallbackConfiguration {
24     @Autowired
25     private PayCallbackConfigMapper payCallbackConfigMapper;
26 
27     @Bean
28     UselessBean uselessBean(){
29         List<PayCallbackConfig> list = payCallbackConfigMapper.listAllVaild();
30         if(null != list && !list.isEmpty()){
31             for(PayCallbackConfig item : list){
32                 PayCallbackUtils.init(item.getSystemId(), item.getRegistryAddress(), item.getRegistryGroup(), item.getRegistryVersion());
33             }
34         }
35         UselessBean uselessBean = new UselessBean();
36         return uselessBean;
37     }
38     
39 }

其中UselessBean就是一个空的类,定义这个就是利用spring对该类的初始来帮我初始化PayCallbackUtils类。

package xx.utils;

/**
 * 不会用的一个bean,只是用来在@Configuration帮忙初始化PayCallbackUtils的数据
 * 
 * @author yangzhilong
 *
 */
public class UselessBean {

}

真正的核心类:PayCallbackUtils

  1 package xx.utils;
  2 
  3 import java.util.Map;
  4 import java.util.concurrent.ConcurrentHashMap;
  5 
  6 import com.alibaba.dubbo.config.ApplicationConfig;
  7 import com.alibaba.dubbo.config.ReferenceConfig;
  8 import com.alibaba.dubbo.config.RegistryConfig;
  9 import xx.api.payment.HuaPayCallbackService;
 10 import xx.dto.payment.HuapayCallbackDTO;
 11 
 12 public class PayCallbackUtils {
 13     // 当前应用的信息
 14     private static ApplicationConfig application = new ApplicationConfig();
 15     // 注册中心信息缓存
 16     private static Map<String, RegistryConfig> registryConfigCache = new ConcurrentHashMap<>();
 17     // 各个业务方的ReferenceConfig缓存
 18     private static Map<String, ReferenceConfig<HuaPayCallbackService>> referenceCache = new ConcurrentHashMap<>();
 19 
 20     static {
 21         application.setName("test");
 22     }
 23 
 24     /**
 25      * 获取注册中心信息
 26      * 
 27      * @param address
 28      *            zk注册地址
 29      * @param group
 30      *            dubbo服务所在的组
 31      * @return
 32      */
 33     private static RegistryConfig getRegistryConfig(String address, String group, String version) {
 34         String key = address + "-" + group + "-" + version;
 35         RegistryConfig registryConfig = registryConfigCache.get(key);
 36         if (null == registryConfig) {
 37             registryConfig = new RegistryConfig();
 38             registryConfig.setAddress(address);
 39             registryConfig.setGroup(group);
 40 
 41             registryConfigCache.put(key, registryConfig);
 42         }
 43         return registryConfig;
 44     }
 45 
 46     /**
 47      * 获取服务的代理对象
 48      * 
 49      * @param business
 50      * @param address
 51      * @param group
 52      * @return
 53      */
 54     private static ReferenceConfig<HuaPayCallbackService> getReferenceConfig(String business, String address,
 55             String group, String version) {
 56         String referenceKey = business;
 57         ReferenceConfig<HuaPayCallbackService> referenceConfig = referenceCache.get(referenceKey);
 58         if (null == referenceConfig) {
 59             referenceConfig = new ReferenceConfig<>();
 60             referenceConfig.setApplication(application);
 61             referenceConfig.setRegistry(getRegistryConfig(address, group, version));
 62             referenceConfig.setInterface(HuaPayCallbackService.class);
 63             referenceConfig.setVersion(version);
 64 
 65             referenceCache.put(referenceKey, referenceConfig);
 66         }
 67         return referenceConfig;
 68     }
 69 
 70     /**
 71      * 初始化数据
 72      * 
 73      * @param business
 74      * @param address
 75      * @param group
 76      * @param version
 77      */
 78     public static void init(String business, String address, String group, String version) {
 79         getReferenceConfig(business, address, group, version);
 80     }
 81 
 82     /**
 83      * 调用远程服务
 84      * 
 85      * @param business
 86      * @param address
 87      * @param group
 88      * @param version
 89      * @return
 90      */
 91     public static boolean invoke(String business, PayCallbackDTO dto) {
 92         ReferenceConfig<PayCallbackService> reference = getReferenceConfig(business, null, null, null);
 93         if (null != reference) {
 94             PayCallbackService callbackService = reference.get();
 95             if (null != callbackService) {
 96                 return callbackService.callback(dto);
 97             }
 98         }
 99         return false;
100     }
101 }

其中HuaPayCallbackService是我定义的支付回调的接口定义,业务系统的回调服务必须实现我这个接口。

示例代码如下:

 1 package xx.api.payment;
 2 
 3 import xx.dto.payment.PayCallbackDTO;
 4 
 5 /**
 6  * 支付异步回调统一的接口
 7  * 
 8  * @author yangzhilong
 9  *
10  */
11 public interface PayCallbackService {
12     /**
13      * 回调的接口
14      * 
15      * @param callbackDTO
16      * @return 成功我就不会再回调,失败我会有重试的机制
17      */
18     boolean callback(HuapayCallbackDTO callbackDTO);
19 }

回调参数的DTO:

package xx.gateway.dto.payment;

import java.io.Serializable;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper = false)
public class PayCallbackDTO implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = -3475086707314113975L;
    /**
     * 支付状态  {@link xx.PaymentConstants.PAY_STATUS}
     */
    private String payStatus;
    /**
     * 支付失败的原因
     */
    private String payErrorInfo;
    /**
     * 业务系统订单id
     */
    private String businessOrderId;
    /**
     * 支付流水id
     */
    private String payFlowId;
    /**
     * 支付渠道返回的code
     */
    private String channelRetCode;
    /**
     * 金额,单位:元
     */
    private String money;
}

 

本文参考DUBBO官方文档实现:http://dubbo.io/API+Config-zh.htm

posted @ 2017-03-13 11:37  自行车上的程序员  阅读(15328)  评论(0编辑  收藏  举报