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×tamp=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