dubbo源码阅读之Provider初始化

1、dubbo provider

dubbo provider是服务提供者,在dubbo中的一个数据模型。

在soa系统中,服务若需要对外暴露,那么dubbo作为一个RPC框架是一个好的选择。

例如在一个application中,简单的配置provider.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans.xsd       
	http://code.alibabatech.com/schema/dubbo        
	http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

	<!-- 提供方应用信息,用于计算依赖关系 -->
	<dubbo:application name="hello-world-app" />

	<!-- 使用multicast广播注册中心暴露服务地址 -->
	<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181" />

	<!-- 用dubbo协议在20880端口暴露服务 -->
	<dubbo:protocol name="dubbo" port="20880" />

	<!-- 声明需要暴露的服务接口 -->
	<dubbo:service interface="com.bailei.dubbo.demo.DemoService"
		ref="demoService" class="com.bailei.dubbo.demo.DemoServiceImpl"
		version="1.0.0" timeout="5000" retries="3" async="false">
		<dubbo:method name="sayHello" timeout="3000" retries="2"
			async="false">
		</dubbo:method>
		<property name="test" value="test" />
	</dubbo:service>

	<!-- <dubbo:service ref="demoService" interface="com.bailei.dubbo.demo.DemoService" 
		></dubbo:service> -->
	<!-- 和本地bean一样实现服务 -->
	<bean id="demoService" class="com.bailei.dubbo.demo.DemoServiceImpl" />

</beans>

就将接口DemoService对外以dubbo协议方式暴露出去了,想调用此服务的application只需要配置相应的consumer配置

consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xsi:schemaLocation="http://www.springframework.org/schema/beans      
	http://www.springframework.org/schema/beans/spring-beans.xsd       
	http://code.alibabatech.com/schema/dubbo       
	http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

	<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
	<dubbo:application name="consumer-of-helloworld-app" />

	<!-- 使用zookeeper广播注册中心暴露发现服务地址 -->
	 <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>
	 
	<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
	<dubbo:reference id="demoService"
		interface="com.bailei.dubbo.demo.DemoService" version="1.0.0" />

</beans>

更详细<dubbo:service>配置请参见 官方文档

  • 2、我们先跑个例子

DemoService.java接口,对外暴露的接口

/**
 * 
 */
package com.bailei.dubbo.demo;

import java.util.Map;

import com.alibaba.dubbo.config.ProtocolConfig;

/**
 * @author bailei
 *
 */
public interface DemoService {
	public String sayHello(String name);
	
	public String testMethod(Map map, ProtocolConfig config) ;
}

上面接口的实现类:DemoServiceImpl.java

/**
 * 
 */
package com.bailei.dubbo.demo;

import java.util.Map;

import com.alibaba.dubbo.config.ProtocolConfig;

/**
 * @author bailei
 *
 */
public class DemoServiceImpl implements DemoService {

	private String privateString;
	
	public String publicString;
	
	protected String protectedString;
	
	
	@Override
	public String sayHello(String name) {
		return "Hello " + name;
	}

	@Override
	public String testMethod(Map map, ProtocolConfig config) {
		// TODO Auto-generated method stub
		return null;
	}

	public String getPrivateString() {
		return privateString;
	}

	public void setPrivateString(String privateString) {
		this.privateString = privateString;
	}

	public String getPublicString() {
		return publicString;
	}

	public void setPublicString(String publicString) {
		this.publicString = publicString;
	}

	public String getProtectedString() {
		return protectedString;
	}

	public void setProtectedString(String protectedString) {
		this.protectedString = protectedString;
	}

	
}

Provider.java 服务提供者application

package com.bailei.dubbo.demo;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Hello world!
 *
 */
public class Provider {

	public static void main(String[] args) throws Exception {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "classpath:provider.xml" });
		context.start();

		System.in.read(); // 按任意键退出
	}

}

 Consumer.java 消费者application

ackage com.bailei.dubbo.demo;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Consumer {
	public static void main(String[] args) throws Exception {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "classpath:consumer.xml" });
		context.start();

		DemoService demoService = (DemoService) context.getBean("demoService"); // 获取远程服务代理
		String hello = demoService.sayHello("world"); // 执行远程方法

		System.out.println(hello); // 显示调用结果
		
		System.in.read();
	}
}
 

 跑出来的结果:

将Provider启动,之后将Consumers启动,Consumer的控制台应该打印出Hello Word

实际上确实调用成功了。

 

这个过程实际上参与方有三个:

registry 、provider、consumer

 

官方dubbo架构图



 

 

上图中的Monitor暂时没有用到。

 

图中Registry是注册中心,本文中使用的zookeeper,dubbo支持多种注册中心。

包含Provider的Container本文中是java application。provider是提供服务方,在启动时,连接到注册中心,将服务相关信息以某种格式(dubbo自定义模型URL)存放在注册中心。下图有zookeeper存放节点的具体内容。



 

consumer是服务消费方,以长连接到注册中心后,订阅需要的服务,如com.bailei.dubbo.demo.DemoService。通过这个在zookeeper节点中拿到具体的providers下面的信息(URL),完成服务的订阅。

 

当provider有更新时,会发送给注册中心,注册中心会及时将更新推送给consumer。

 

 具体调用过程:消费方发起远程调用时,首先应该拿到调用接口提供方的相关信息,就像http请求,起码得知道ip和端口啊。从注册中心拿到的信息可以找到提供者providers信息。

里面具体是这样子的:(经过URLDecode)

dubbo://192.168.144.104:20880/com.bailei.dubbo.demo.DemoService?any
host=true&application=hello-world-app&class=com.bailei.dubbo.demo.Demo
ServiceImpl&dubbo=2.0.0&generic=false&interface=com.bailei.dubbo.dem
o.DemoService&methods=sayHello,testMethod&pid=5648&retries=3&rev
ision=1.0.0&sayHello.retries=2&sayHello.timeout=3000&side=provider
&timeout=5000×tamp=1442937194957&version=1.0.0

 

以dubbo开头说明使用的是dubbo协议作为rpc protocol,后面的博客会讲到。

可以发现provider.xml配置的一些信息,都以url形式存放起来了。

消费方可以通过接口查找到这样的信息,然后由这样的信息调用到具体的服务提供方com.bailei.dubbo.demo.DemoService,中间的细节,后面的博客会讲到。

 

  • 3、Provider如何初始化的

    3.1、基于Spring的配置

 从provider.xml元素标签可知,dubbo有自己的spring扩展。在dubbo源码项目中:

dubbo-config-spring META-INF/dubbo.xsd、spring.handlers、spring.schemas。这是标准的自定义spring配置三件套啊。

spring.handlers内容如下:

http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

 

这个类扩展于spring的NamespaceHandlerSupport,省略了import

/**
 * DubboNamespaceHandler
 * 
 * @author william.liangf
 * @export
 */
public class DubboNamespaceHandler extends NamespaceHandlerSupport {

	static {
		Version.checkDuplicate(DubboNamespaceHandler.class);
	}

	public void init() {
	    registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
    }

}

 

spring解析xml配置时,遇到自定义命名空间元素,会先去加载spring.handlers文件,获取到自定义命名空间解析处理的类,通过classloader加载实例化

,DubboNamespaceHandler初始化时,注册需要自己解析的元素名及对应的类名。

provider初始化,重点初始化两个类,数据模型类:

1、ProviderConfig

2、ServiceBean

未完待续。。。。。。。。。。。。

猜你喜欢

转载自sonymoon.iteye.com/blog/2245160