为了更好的阅读体验,请点击这里跳转到最新的文章:《Dubbo配置方式详解》
Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是阿里巴巴 SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。
Dubbo 采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。
根据 DUBBO 官方文档,配置 DUBBO 有 4 种方式,分别是:
-
- 1. XML 配置文件方式
- 2. properties 配置文件方式
- 3. annotation 配置方式
- 4. API 配置方式
- 这里我们只介绍前两种方式的配置。
1、XML 配置文件方式
创建 DubboDemo 项目,并创建 interface 模块、provider 模块、consumer 模块,它们都是 DubboDemo 的子模块。其中 interface 模块存放所有的接口、provider 模块提供服务、consumer 消费服务。创建完成后的项目结构如下:
在 DubboDemo 模块 pom.xml 加入如下依赖,为所有模块提供 JUnit 和 LOG4J 依赖。
3.8.1
junit
junit
${junit.version}
test
org.slf4j
slf4j-api
1.7.6
org.slf4j
slf4j-log4j12
1.7.6
同时在 provider 模块和 consumer 模块的 resources 目录里加入 log4j.properties 配置文件:


#Console Log
log4j.rootLogger=info, console, file
# Write to Console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=INFO
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%5p %d{MM-dd HH:mm:ss}(%F:%L): %m%n
#Write to File
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=${catalina.home}log/provider.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%5p %d{MM-dd HH:mm:ss}(%F:%L): %m%n
在 interface 模块中创建接口 com.chanshuyi.service.IUserService:


package com.chanshuyi.service;
/**
* Created by chanshuyi on 2016/1/19.
*/
public interface IUserService {
/**
* 登录方法
* @return 是否登录成功
*/
public boolean login(String username, String password);
}
interface 模块配置完毕。
在 provider 模块中引入 Spring、Dubbo、interface 模块依赖:


<properties> <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> <junit.version>3.8.1junit.version> <springframework.version>4.1.6.RELEASEspringframework.version> <commonsLogging.version>1.2commonsLogging.version> properties> <dependencies> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-coreartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-txartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-ormartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-jdbcartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-webartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-contextartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-beansartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>commons-logginggroupId> <artifactId>commons-loggingartifactId> <version>${commonsLogging.version}version> dependency> <dependency> <groupId>org.aspectjgroupId> <artifactId>aspectjweaverartifactId> <version>1.8.5version> dependency> <dependency> <groupId>com.alibabagroupId> <artifactId>dubboartifactId> <version>2.5.3version> <exclusions> <exclusion> <groupId>org.springframeworkgroupId> <artifactId>springartifactId> exclusion> exclusions> dependency> <dependency> <groupId>org.apache.zookeepergroupId> <artifactId>zookeeperartifactId> <version>3.3.3version> <exclusions> <exclusion> <groupId>com.sun.jmxgroupId> <artifactId>jmxriartifactId> exclusion> <exclusion> <groupId>com.sun.jdmkgroupId> <artifactId>jmxtoolsartifactId> exclusion> <exclusion> <groupId>javax.jmsgroupId> <artifactId>jmsartifactId> exclusion> exclusions> dependency> <dependency> <groupId>com.github.sgroschupfgroupId> <artifactId>zkclientartifactId> <version>0.1version> dependency> <dependency> <groupId>com.chanshuyi.DubboDemogroupId> <artifactId>interfaceartifactId> <version>1.0-SNAPSHOTversion> dependency> dependencies>
创建 com.chanshuyi.service.impl.UserServiceImpl 类,实现 IUserService 接口:
package com.chanshuyi.service.impl;
import com.chanshuyi.service.IUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* Created by chanshuyi on 2016/1/19.
*/
@Service("userService")
public class UserServiceImpl implements IUserService {
private Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
@Override
public boolean login(String username, String password) {
logger.info("用户登录:[username:{}, password:{}]", username, password);
if (username != null && password != null && username.equals(password)) {
logger.info("用户校验通过。[username:{}]", username);
return true;
}
logger.info("用户校验失败![username:{}]", username);
return false;
}
}
创建 Spring 配置文件,配置注解扫描 com.chanshuyi.service.impl 包,并引入 spring-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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.chanshuyi.service.impl"/> <import resource="spring-provider.xml"/> beans>
注意!这里不要写成 com.chanshuyi.service.impl.* 否则无法成功扫描!
创建 spring-provider.xml 文件,它是 dubbo 的主要配置文件。
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="dubbodemo-provider"/> <dubbo:registry id="dubbodemo" address="zookeeper://localhost:2181"/> <dubbo:protocol name="dubbo" port="28080"/> <dubbo:service registry="dubbodemo" timeout="3000" interface="com.chanshuyi.service.IUserService" ref="userService"/> beans>
可以看到这里有几个关键参数:application、registry、protocol、service。
-
- application 指当前应用名称,主要用来给 zookeeper 注册中心计算应用间依赖关系。
- registry 用来声明一个注册中心,这里声明了一个id 为 registry 的注册中心,地址是本地服务器的 2181 端口(这里要与 zookeeper 配置文件的 clientPort 属性值一致)。
- protocol 指该应用用 dubbo 协议在 28080 端口暴露服务,其他应用可以通过这个接口调用服务。
- service 用来声明需要暴露的服务接口,这里暴露了IUserService 接口,并将接口注册到 id 为 dubbodemo 的注册中心,它引用了 Spring 中名为 userService 的类,超时时间为 3 秒。
到这里 provider 提供者的配置基本上完成,但我们还需要写一个启动类将 provider 启动起来提供服务。
创建 com.chanshuyi.util.BeanFactoryUtil.java,是加载 Spring 的工具类:


package com.chanshuyi.util; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class BeanFactoryUtil { private static ApplicationContext ctx_producer = null; public final static String ApplicationContextRoot = ""; public final static String ApplicationContextPath = ApplicationContextRoot + "applicationContext.xml"; public static void init() { if (ctx_producer == null) { synchronized (BeanFactoryUtil.class) { if(ctx_producer == null){ String[] configLocations = new String[]{ApplicationContextPath}; ctx_producer = new ClassPathXmlApplicationContext(configLocations); } } } } public static ApplicationContext getContext() { init(); return ctx_producer; } }
创建 com.chanshuyi.util.SystemDetails.java,用于输出系统信息:


package com.chanshuyi.util; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; public class SystemDetails { /** * 输出系统基本信息 */ public static void outputDetails() { timeZone(); currentTime(); os(); } /** * 输出系统时区 */ private static void timeZone() { Calendar cal = Calendar.getInstance(); TimeZone timeZone = cal.getTimeZone(); System.out.println("系统时区:" + timeZone.getDisplayName()); } /** * 输出系统时间 */ private static void currentTime() { String fromFormat = "yyyy-MM-dd HH:mm:ss"; SimpleDateFormat format = new SimpleDateFormat(fromFormat); Date myDate = new Date(); System.out.println("系统时间:" + format.format(myDate)); } /** * 输出系统基本配置 */ private static void os() { String osName = System.getProperty("os.name"); //操作系统名称 System.out.println("当前系统:" + osName); String osArch = System.getProperty("os.arch"); //操作系统构架 System.out.println("当前系统架构" + osArch); String osVersion = System.getProperty("os.version"); //操作系统版本 System.out.println("当前系统版本:" + osVersion); } }
创建 com.chanshuyi.Launcher.java,用于启动 provider 服务,是启动入口:


package com.chanshuyi; import com.chanshuyi.util.BeanFactoryUtil; import com.chanshuyi.util.SystemDetails; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class Launcher { private static Log logger = LogFactory.getLog(Launcher.class); /** * @param args */ public static void main(String[] args) { System.out.println("======================="); System.out.println(" Core包启动 "); SystemDetails.outputDetails(); System.out.println("======================="); getLocalip(); // 初始化spring logger.info("开始初始化core服务"); BeanFactoryUtil.init(); try{ System.in.read(); } catch (Exception e) { e.printStackTrace(); } } /** * 取得本机ip地址 注意:Spring RmiServiceExporter取得本机ip的方法:InetAddress.getLocalHost() */ private static void getLocalip() { try { System.out.println("服务暴露的ip: " + java.net.InetAddress.getLocalHost().getHostAddress()); } catch (Exception e) { System.out.println(e.getMessage()); } } }
到这里 provider 模块配置结束。我们运行 Launcher.main() 方法启动服务,并打开 zookeeper 注册中心(点击这里下载,双击 bin/zkServer.cmd 运行即可),启动 provider 服务。
接下来我们编写 consumer 代码。
在 consumer 的 pom.xml 中导入 Spring、dubbo、interface 模块依赖


<properties> <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> <junit.version>3.8.1junit.version> <springframework.version>4.1.6.RELEASEspringframework.version> <commonsLogging.version>1.2commonsLogging.version> properties> <dependencies> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-coreartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-txartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-ormartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-jdbcartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-webartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-contextartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-beansartifactId> <version>${springframework.version}version> dependency> <dependency> <groupId>commons-logginggroupId> <artifactId>commons-loggingartifactId> <version>${commonsLogging.version}version> dependency> <dependency> <groupId>org.aspectjgroupId> <artifactId>aspectjweaverartifactId> <version>1.8.5version> dependency> <dependency> <groupId>com.alibabagroupId> <artifactId>dubboartifactId> <version>2.5.3version> <exclusions> <exclusion> <groupId>org.springframeworkgroupId> <artifactId>springartifactId> exclusion> exclusions> dependency> <dependency> <groupId>org.apache.zookeepergroupId> <artifactId>zookeeperartifactId> <version>3.3.3version> <exclusions> <exclusion> <groupId>com.sun.jmxgroupId> <artifactId>jmxriartifactId> exclusion> <exclusion> <groupId>com.sun.jdmkgroupId> <artifactId>jmxtoolsartifactId> exclusion> <exclusion> <groupId>javax.jmsgroupId> <artifactId>jmsartifactId> exclusion> exclusions> dependency> <dependency> <groupId>com.github.sgroschupfgroupId> <artifactId>zkclientartifactId> <version>0.1version> dependency> <dependency> <groupId>com.chanshuyi.DubboDemogroupId> <artifactId>interfaceartifactId> <version>1.0-SNAPSHOTversion> dependency>
创建类 com.chanshuyi.UserServiceConsumer.java


package com.chanshuyi; import com.chanshuyi.service.IUserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by Administrator on 2016/1/19. */ public class UserServiceConsumer { private static Logger logger = LoggerFactory.getLogger(UserServiceConsumer.class); public static void main(String args[]) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); IUserService userService = (IUserService) ctx.getBean("userService"); logger.info("执行结果:" + userService.login("hello", "hello")); } }
配置 applicationContext.xml 文件以及 spring-consumer.java 文件


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


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="dubbodemo-consumer"/> <dubbo:registry address="zookeeper://localhost:2181"/> <dubbo:protocol port="28080"/> <dubbo:reference id="userService" interface="com.chanshuyi.service.IUserService"/> beans>
spring-consumer.xml 的配置大致与 spring-provider.xml 相同,只是 dubbo:service 节点换成 dubbo:reference 节点。
到这里 consumer 模块配置基本结束。我们运行 UserServiceConsumer.main() 方法调用 provider 服务(provider 服务要开启哦),成功之后会打印出是否调用成功。
如果这样就表示成功调用了。可以看到 DUBBO 框架是在 Spring 的基础上加上一个简单的配置文件即可把一个服务暴露出去。
DUBBO 配置文件基本有 application、registry、protocol 3个公共参数分别告诉了 DUBBO 以及 zookeeper 注册中心:我是谁?我向谁注册?怎么调用我的服务? 通过这 3 个配置,其他消费者就可以找到对应服务。
2、properties 配置文件方式
DUBBO 在读取配置的时候会先读取 XML文件中的配置,如果没找到就会默认去读取resources目录下的 dubbo.properties 文件。而 dubbo.properties 的配置方式与 XML配置方式一样,只不过是换了种写法而已。要换成 dubbo.properties 配置,你只需把 spring-provider.xml 里关于 application、registry、protocol 里的配置注释掉,然后加上对应的 dubbo.properties 文件即可。上面例子的 spring-provider.xml 换成 properties 文件的写法是这样的:
# 应用名
dubbo.application.name=dubbodemo-provider
# 注册中心地址
dubbo.registry.address=zookeeper://localhost:2181
# 调用协议地址
dubbo.protocol.name=dubbo
dubbo.protocol.port=28080
spring-consumer.xml 换成 properties 文件写法是这样的:
# 应用名
dubbo.application.name = dubbodemo-consumer
# 注册中心地址
dubbo.registry.address = zookeeper://localhost:2181
# 调用协议地址
dubbo.protocol.name = dubbo
dubbo.protocol.port = 28080
此时 spring-provider.xml 和 spring-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:service timeout="3000" interface="com.chanshuyi.service.IUserService" ref="userService"/> beans>


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:reference id="userService" interface="com.chanshuyi.service.IUserService"/> beans>
注意,如果你即配置了 XML 又配置了 properties 的内容,那么 DUBBO 读取时将直接读取 XML 中的配置,忽略 properties 里的配置。
一般情况下 properties 都是用来配置一些公共的信息,比如可能一个应用需要调用多个注册中心的服务,这时候它们的 application.name、dubbo.protocol.name等都是相同的,那么你可以用 properties 来配置这些公共信息。其他情况,还是建议用 XML 配置方式。
3、annotation 配置方式
annotation 配置方式其实是在 XML 配置方式上,将暴露服务和调用服务与 Spring 深度结合起来。
Provider 方配置
将
<dubbo:annotation package="com.chanshuyi.service.impl" />
其中 package 表示要扫描的包。之后在实现类里加上注解 @Service(version = "1.0.0") :
package com.chanshuyi.service.impl;
import com.chanshuyi.service.IUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.dubbo.config.annotation.Service;
@Service(version = "1.0.0")
public class UserServiceImpl implements IUserService {
@Override
public boolean login(String username, String password) {
……
}
}
注意这里用的 @Service 注解是 alibaba.dubbo 中的 Service 注解。
Consumer 方配置
将
<dubbo:annotation package="com.chanshuyi" />
其中 package 表示要扫描的包。之后在需要注入的服务里加上注解 @Reference(version="1.0.0"),修改后的 UserServiceConsumer.java 为:
package com.chanshuyi; import com.chanshuyi.service.IUserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; import com.alibaba.dubbo.config.annotation.Reference; /** * Created by chanshuyi on 2016/1/19. */ @Component public class UserServiceConsumer { private static Logger logger = LoggerFactory.getLogger(UserServiceConsumer.class); @Reference(version="1.0.0") static IUserService userService; public static void main(String args[]) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); logger.info("执行结果:" + userService.login("hello", "hello")); } }
之后启动 provider服务,运行 UserServiceConsumer.main() 方法测试。
本文项目文件链接:http://pan.baidu.com/s/1kTYOtKV 密码:d4cu
参考资料:
1. http://dubbo.io/
2. DUBBO 官方配置参考手册