Dubbo简介
Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbo这样的分布式服务框架的需求,并且本质上是个服务调用的东东,说白了就是个远程服务调用的分布式框架(告别Web Service模式中的WSdl,以服务者与消费者的方式在dubbo上注册)
Dubbo提供了三个关键功能:基于接口的远程调用,容错与负载均衡,服务自动注册与发现。
1.透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
2.软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
3. 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
dubbo架构图如下所示
Provider: 暴露服务的服务提供方。
Consumer: 调用远程服务的服务消费方。
Registry: 服务注册与发现的注册中心。
Monitor: 统计服务的调用次调和调用时间的监控中心。
Container: 服务运行容器。
调用关系说明:
0 服务容器负责启动,加载,运行服务提供者。
1. 服务提供者在启动时,向注册中心注册自己提供的服务。
2. 服务消费者在启动时,向注册中心订阅自己所需的服务。
3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
Dubbo的使用
生产者
<!--提供方应用信息,用于计算依赖关系 名字是什么无所谓:dubbo-admin后台显示的应用名-->
<dubbo:application name="paycenter-server" logger="log4j" version="${dubbo.service.version}" organization="paycenter" environment="${dubbo.environment}"/>
<!--用zookeeper作为注册中心 -->
<dubbo:registry protocol="zookeeper" address="${dubbo.registry.address}" file="${catalina.home}/dubbo-registry/dubbo-registry.properties"/>
<!--bubbo负载模式 loadbalance="roundrobin" -->
<dubbo:provider protocol="dubbo" loadbalance="${dubbo.loadbalance}" />
<!--<dubbo:monitor protocol="registry"/>-->
<!--用dubbo的协议 在dubbo.protocol.accepts=20880/500端口暴露服务
下面会有修改协议暴露端口信息 -->
<dubbo:protocol name="dubbo" accepts="${dubbo.protocol.accepts}"/>
<dubbo:protocol name="jsonrpc" server="jetty"/>
<!--修改协议暴露端口信息 下面是配置文件中配置的暴露端口信息
dubbo.ports=28005,28006,28007,28008
dubbo.jsonrpc.ports=9995,9996,9997,9998-->
<bean class="com.paycenter.dubbo.DynamicDubboPortReaderImpl" init-method="init">
<property name="protocolName" value="dubbo"/>
<property name="ports" value="${dubbo.ports}"/>
</bean>
<bean class="com.paycenter.dubbo.DynamicDubboPortReaderImpl" init-method="init">
<property name="protocolName" value="jsonrpc"/>
<property name="ports" value="${dubbo.jsonrpc.ports}"/>
</bean>
<!-- 声明需要暴露的服务接口
retries="0"重试次数 写操作可以设置为0 避免重复调用SOA服务-->
<dubbo:service protocol="dubbo,jsonrpc" interface="com.paycenter.api.service.IPayCenterFacade"
ref="payFacade" timeout="${dubbo.timeout}" retries="${dubbo.retries}"/>
public class DynamicDubboPortReaderImpl implements ApplicationContextAware {
private ConfigurableApplicationContext applicationContext = null;
private String protocolName;
private String ports = null;
/* 初始化方法 */
public void init() {
updateProtocolMessage(protocolName, getAddressPort());
}
public Integer getAddressPort() {
if (ports == null) {
return null;
}
for (String port : ports.split(",")) {
Integer iport= Integer.valueOf(port);
if(!isLoclePortUsing(iport)){
return iport;
}
}
return null;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
public void updateProtocolMessage(String protocolConfig, Integer port) {
if (port != null) {
// 判断初始化
if (!applicationContext.containsBean(protocolConfig)) {
System.out.println("没有【" + protocolConfig + "】协议");
}
// 获取协议
ProtocolConfig protocolConfigSource = (ProtocolConfig) applicationContext.getBean(protocolConfig);
// 修改协议暴露端口信息
protocolConfigSource.setPort(port);
}
}
/***
* true:already in using false:not using
*/
public static boolean isLoclePortUsing(int port) {
boolean flag = true;
try {
flag = isPortUsing("127.0.0.1", port);
} catch (Exception e) {
flag = false;
}
return flag;
}
/***
* true:already in using false:not using
*/
public static boolean isPortUsing(String host, int port)throws UnknownHostException {
boolean flag = false;
InetAddress theAddress = InetAddress.getByName(host);
Socket socket =null;
try {
socket = new Socket(theAddress, port);
flag = true;
} catch (IOException e) {
flag = false;
}finally{
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return flag;
}
public String getPorts() {
return ports;
}
public void setPorts(String ports) {
this.ports = ports;
}
public String getProtocolName() {
return protocolName;
}
public void setProtocolName(String protocolName) {
this.protocolName = protocolName;
}
}
消费者
<!--消费方应用名称,用于计算依赖关系 不是匹配条件,不要与提供方一样 -->
<dubbo:application name="paycenter-web" logger="log4j" version="${dubbo.service.version}" organization="merchant" environment="${dubbo.environment}"/>
<dubbo:registry protocol="zookeeper" address="${dubbo.registry.address}" file="${catalina.home}/dubbo-registry/dubbo-registry.properties"/>
<!--生成远程服务代理
id :是自己定义的(随便取)
interface :一定要和服务提供方一致
check="false" 检查级联依赖关系,默认为true,当有依赖服务的时候,需要根据需求进行设置-->
<dubbo:reference id="payCenterFacade" protocol="dubbo" interface="com.paycenter.api.service.IPayCenterFacade"
timeout="${dubbo.timeout}" lazy="true" loadbalance="${dubbo.loadbalance}"
retries="${dubbo.retries}" check="false" mock=""/>
@Controller
public class QuickPaymentConfirmController extends BaseController {
@Autowired
private IPayCenterFacade payCenterFacade;
@RequestMapping(value = "/quickPaymentConfirm", method = RequestMethod.POST)
@ResponseBody
public void quickPaymentConfirm(HttpServletRequest request) throws Exception {
String jsonStr = getRequestString(request);
//直接调用dubbo服务
payCenterFacade.invoke(jsonStr,null);
}
}
用原生API不集成Spring调用dubbo服务
public static void main(String[] args) throws Exception {
//创建应用
ApplicationConfig ac = new ApplicationConfig();
ac.setName("paycenter-server");
//创建dubbo地址及接口
ReferenceConfig<IPayCenterFacade> ref = new ReferenceConfig<IPayCenterFacade>();
ref.setInterface(IPayCenterFacade.class);
ref.setUrl("dubbo://192.168.23.1:28005/com.paycenter.api.service.IPayCenterFacade");
ref.setApplication(ac);
//创建dubbo方法
MethodConfig mc = new MethodConfig();
mc.setAsync(false);
mc.setName("invoke");//方法名
ref.setMethods(Arrays.asList(new MethodConfig[]{mc}));
ref.setTimeout(10000);
//创建方法的请求参数
String requestJSON = "{\"biz_system\":5,\"goods_name\":\"测试商品爱国\",\"is_large_amount\":0,\"is_support_credit_card\":1,\"merchant_id\":\"020050210117\",\"notify_url\":\"http://www.baidu.com/\",\"order_no\":\"1540197454831\",\"order_time\":\"20181022163734\",\"pay_channel\":22,\"pay_money\":1,\"sign\":\"d6d80b3750d3f1b726690a2a61741955\",\"third_pay_platform\":\"59\"}";
PaycenterCommunicationDTO commDto = new PaycenterCommunicationDTO();
commDto.setMethod("getQRCode");
//请求接口
BaseResponse invoke = ref.get().invoke(requestJSON, commDto);
System.out.println(invoke);
System.out.println("ok");
}