一、Dubbo简介
1.Dubbo的概念:
DUBBO是一个分布式服务治理框架,致力于提供高性能和透明化的RPC远程服务调用方案,可以和 Spring框架无缝集成,是阿里巴巴SOA服务化治理方案的核心框架,每天为2000+个服务提供3000000000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点,同时,国内有大量的大型平台都是基于Dubbo的分布式服务治理架构完成服务的分布式访问。
Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。
2.Dubbo的作用:
(1)使用一个注册中心来存放大量的服务,动态注册和发现服务。
(2)自动画出应用间的依赖关系图,以帮助架构师理清理关系。
(3)将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。以此信息确定何时需要加减服务器。

3.Dubbo核心要点
① 服务定义
服务是围绕服务提供方和服务消费方的,服务提供方实现服务,而服务消费方调用服务。
② 服务注册
对于服务提供方,它需要发布服务,而且由于应用系统的复杂性,服务的数量、类型也不断膨胀;对于服务消费方,它最关心如何获取到它所需要的服务,而面对复杂的应用系统,需要管理大量的服务调用。而且,对于服务提供方和服务消费方来说,他们还有可能兼具这两种角色,即既需要提供服务,有需要消费服务。
通过将服务统一管理起来,可以有效地优化内部应用对服务发布/使用的流程和管理。服务注册中心可以通过特定协议来完成服务对外的统一。Dubbo提供的注册中心有如下几种类型可供选择:
Multicast(多播/组播)注册中心(开发测试用)、Zookeeper注册中心(生产环境用官方推荐)、Redis注册中心、Simple注册中心
③ 服务监控
无论是服务提供方,还是服务消费方,他们都需要对服务调用的实际状态进行有效的监控,从而改进服务质量。
④ 远程通信与信息交换
远程通信需要指定通信双方所约定的协议,在保证通信双方理解协议语义的基础上,还要保证高效、稳定的消息传输。Dubbo继承了当前主流的网络通信框架,主要包括如下几个:
Mina、Netty、Grizzly
⑤ 服务调用

节点角色说明:
Provider: 暴露服务的服务提供方。
Consumer: 调用远程服务的服务消费方。
Registry: 服务注册与发现的注册中心。
Monitor: 统计服务的调用次调和调用时间的监控中心。
Container: 服务运行容器。
调用关系说明:

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
    4.Dubbo的获取(官网hello world)
    官方Maven仓库
    阿里巴巴已将Dubbo已发布到Maven中央仓库中:
    http://central.maven.org/maven2/com/alibaba/dubbo。
<project>
     <dependencies>
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>dubbo</artifactId>
             <version>2.6.2</version>
         </dependency>
     </dependencies>
 </project>

二、Dubbo本地服务化实现
1.Dubbo服务化架构包含的内容
服务提供者: 提供服务接口的实现,发布服务地址,提供服务。
服务消费者:获取服务地址,使用服务接口调用服务,处理服务调用结果。
公共项目:包含公共配置、DO、VO、工具包等…
2.服务提供者项目搭建(Maven项目管理方式):
① 创建公共项目工程:普通的Maven工程,提供utils、DO、接口的代码。
pom.xml 无任何依赖
② 创建服务提供者项目:普通的Maven工程(依赖Dubbo),提供服务实现、服务启动功能。

pom.xml

<dependencies>
				<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>dubbo</artifactId>
			<version>2.6.2</version>
		</dependency>
		<dependency>
			<groupId>dubbo-api</groupId>
			<artifactId>dubbo-api</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
         <dependency>
    <groupId>com.github.sgroschupf</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.1</version>
</dependency>

	<!-- junit测试包 -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.12</version>
		<scope>test</scope>
	</dependency>

	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-test</artifactId>
		<version>4.3.16.RELEASE</version>
	</dependency>

	
</dependencies>

dubbo-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-2.5.xsd
	http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

	<dubbo:application name="dubbo-test-provider" owner="sampson"></dubbo:application>
	
	<dubbo:protocol name="dubbo" port="20880" ></dubbo:protocol>
	
	<!-- 局域网广播注册中心 -->
	<dubbo:registry address="multicast://239.5.6.7:1234" />
	
	<!-- 配置式发布 -->
	<bean id="userService" class="cn.itsource.dubbo.provider.service.UserServiceImpl"></bean>
	<dubbo:service interface="cn.itsource.dubbo.core.service.IUserService" ref="userService"></dubbo:service>
<!-- 注解式发布 -->
	<!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 -->
	<dubbo:annotation package="cn.itsource.dubbo.provider.service" />
</beans>

启动服务监听

String configLocation = "classpath*:/dubbo-provider.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
System.out.println("dubbo-server服务正在监听,按任意键退出");
System.in.read();

3.服务消费者项目搭建(Maven项目管理方式):
创建服务消费者项目:普通的Maven工程(依赖Dubbo),完成服务调用功能。

pom.xml

<dependencies>
	<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>dubbo</artifactId>
			<version>2.6.2</version>
		</dependency>
<dependency>
			<groupId>dubbo-api</groupId>
			<artifactId>dubbo-api</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
   <dependency>
    <groupId>com.github.sgroschupf</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.1</version>
</dependency>
	</dependencies>

dubbo-consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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-2.5.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd 
http://www.springframework.org/schema/context  
http://www.springframework.org/schema/context/spring-context.xsd">

<dubbo:application name="dubbo-test-consumer"></dubbo:application>

<!-- 局域网广播注册中心 -->
<dubbo:registry address="multicast://239.5.6.7:1234" />
	
<!-- 配置式调用服务 -->

	<!-- <dubbo:reference id="helloService" interface="cn.itsource.dubbo.core.service.IHelloService"></dubbo:reference> -->

<!-- 注解式调用服务 -->
<!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 -->
	<dubbo:annotation package="cn.itsource.dubbo.consumer" />
</beans>

JUnit4调用dubbo服务测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:/dubbo-consumer.xml"})
public class DubboServiceTest {
	@Reference
	private IHelloService helloService;

@Test
public void testHello(){
	String sayHi = helloService.sayHi("老宋");
	System.out.println(sayHi);
}

}

4.直连调试模式
服务提供者:
修改注册中心为:N/A模式(不注册)

<dubbo:registry address="N/A" check="false"/>

服务消费者:
修改注册中心为:N/A模式(不注册)

<dubbo:registry address="N/A" check="false"/>

url 配置属性

<dubbo:reference id="demoService" interface="cn.itsource.dubbo.DemoService"  url="dubbo://localhost:20881" />

配置本地调用地址映射:
然后在${user.home}/dubbo-resolve.properties文件中配置对应服务调用的本地地址
${user.home} 一般代表:C:\Users{你当前登录名}
dubbo-resolve.properties示例

cn.itsource.dubbo.core.service.IUserService=dubbo://localhost:20880

5.Dubbo服务打包
(1)Dubbo服务的运行方式有三种
(2)使用Servlet容器(不用)
利用Tomcat、Jetty等WEB容器启动Dubbo服务。
缺点:增加管理配置的复杂性,不必要地使用http端口,浪费内存资源
(3)Java的Main方法(不建议,本地调试可以用)
基于Spring框架,写一个Java类并提供Main方法启动。
缺点:无法使用Dubbo的一些高级特性,服务的管理需要自己额外提供实现
(4)Dubbo框架Main方法
Dubbo框架本身提供了服务运行支持方法,基于com.alibaba.dubbo.container.Main
简单高效地运行服务
很好地支持Dubbo服务的发布、关停(ShutdownHook)
(5)Maven编译打包

Pom.xml

<groupId>cn.itsource.service</groupId>
	<artifactId>service-user</artifactId>
	<version>${service-user.version}</version>
	<packaging>jar</packaging>
	
<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<!-- 打包jar详细配置 -->
<build>
	<!-- jar包名字 -->
	<finalName>provder</finalName>
	<!-- 打包资源配置,如配置文件 -->
	<resources>
		<resource>
			<targetPath>${project.build.directory}/classes</targetPath>
			<directory>src/main/resources</directory>
			<filtering>true</filtering>
			<includes>
				<include>**/*.xml</include>
				<include>**/*.properties</include>
			</includes>
		</resource>
		<!-- 结合com.alibaba.dubbo.container.Main 
		官方文档:dubbo会自动在classes/META-INF/spring下去加载spring的配置文件
		因此打包时需要将spring配置文件复制到该目录
		-->
		<resource>
			<targetPath>${project.build.directory}/classes/META-INF/spring</targetPath>
			<directory>src/main/resources</directory>
			<filtering>true</filtering>
			<includes>
				<include>applicationContext.xml</include>
			</includes>
		</resource>
	</resources>
	
	<pluginManagement>
		<plugins>
			<!-- 解决Maven插件在Eclipse内执行了一系列的生命周期引起冲突 -->
			<plugin>
				<groupId>org.eclipse.m2e</groupId>
				<artifactId>lifecycle-mapping</artifactId>
				<version>1.0.0</version>
				<configuration>
					<lifecycleMappingMetadata>
						<pluginExecutions>
							<pluginExecution>
								<pluginExecutionFilter>
									<groupId>org.apache.maven.plugins</groupId>
									<artifactId>maven-dependency-plugin</artifactId>
									<versionRange>[2.0,)</versionRange>
									<goals>
										<goal>copy-dependencies</goal>
									</goals>
								</pluginExecutionFilter>
								<action>
									<ignore />
								</action>
							</pluginExecution>
						</pluginExecutions>
					</lifecycleMappingMetadata>
				</configuration>
			</plugin>
		</plugins>
	</pluginManagement>
	<plugins>
		<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-jar-plugin</artifactId>
			<configuration>
				<classesDirectory>target/classes/</classesDirectory>
				<archive>
					<manifest>
						<mainClass>com.alibaba.dubbo.container.Main</mainClass>
						<!-- 重要:打包时 MANIFEST.MF文件不记录的时间戳版本 -->
						<useUniqueVersions>false</useUniqueVersions>
						<addClasspath>true</addClasspath>
						<classpathPrefix>lib/</classpathPrefix>
					</manifest>
					<manifestEntries>
						<Class-Path>.</Class-Path>
					</manifestEntries>
				</archive>
			</configuration>
		</plugin>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-dependency-plugin</artifactId>
			<executions>
				<execution>
					<id>copy-dependencies</id>
					<phase>package</phase>
					<goals>
						<goal>copy-dependencies</goal>
					</goals>
					<configuration>
						<type>jar</type>
						<includeTypes>jar</includeTypes>
						<useUniqueVersions>false</useUniqueVersions>
						<outputDirectory>
							${project.build.directory}/lib
						</outputDirectory>
					</configuration>
				</execution>
			</executions>
		</plugin>
	</plugins>

</build>

<dependencies>
</dependencies>

(3)dubbo服务jar包运行
Cmd窗口:
① 定位到jar包所在目录
② 输入命令并回车执行:java -jar xxxxx.jar
三.P2P项目的分布式服务调用实现(crm)
1.作用
主要是对原有的代码进行重新整合,分为代码拆分、dubbo集成(分离出服务提供方和消费方)、服务发布与接入(注册中心zookeeper)
2.代码拆分
根据各层进行拆分,主要针对:
① pom.xml项目引用jar包
② 代码:DAO和Service层独立为服务提供者。前端和Controller独立为服务消费者。
③ Spring配置文件进行拆分(参考②步拆分思路)
注意:利用tomcat插件启动web需要设置tomcat的calsspath选中依赖的项目
Idea 需要

<resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.*</include>
            </includes>
            <excludes>
                <exclude>**/*.java</exclude>
            </excludes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.*</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>

3.Dubbo集成
对服务提供方和服务消费者集成Dubbo的调用方式。
公共项目:
因为Dubbo涉及远程调用传输对象,所有需要传输的对象的类都必须实现Serializable接口,如Domain层的所有类。
(1)服务提供方
① 修改原spring的@Service注解为dubbo的@Service注解
② 新建xxxx-dubbo-provider.xml,然后在spring contex的配置文件最后引入
Xxxx-dubbo-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服务发布 -->
	<dubbo:application name="p2p-service" />
	<dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>
	<dubbo:registry address="multicast://239.5.6.7:1236"></dubbo:registry>
	<dubbo:annotation package="cn.itsource.eloan.core.service.impl" />
</beans>

③ 服务发布类

public class DubboServer {
	public static void main(String[] args) throws IOException {
		String configLocation = "classpath*:/spring-core.xml";
		ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
		System.out.println("p2p服务正在监听");
		String[] names = context.getBeanDefinitionNames();
		System.out.print("Beans:");
		for (String string : names)
			System.out.println(string);
		System.out.println();
		System.in.read();
	}
}

(2)服务消费方
① 修改需要远程调用的服务,从原spring的@Autoware注解为dubbo的@Reference注解
② 新建xxxx-dubbo-consumer.xml,然后在springmvc contex的配置文件最后引入
Xxxx-dubbo-consumer.xml