前言
《深入理解Apache Dubbo与实战》第二章阅读笔记,内容主要是通过xml,注解以及api的方式实现第一个dubbo程序。其中遇到了一些坑,比如依赖的配置,因为书上并没有介绍依赖的配置,本人花了一段时间才解决。
一、工程结构与依赖
总的结构如图所示,父工程是echo。echo-api里是服务的接口,echo-server,echo-client是使用xml方式的服务器与客户端。echo-server-annotation,echo-client-annotation是使用注解方式的服务器与客户端,echo-java-server和echo-java-client是使用api方式的服务器与客户端。
依赖主要是下面
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>
版本号应该无所谓,由于使用spring的方式导入依赖有非常多的依赖,最开始的时候一直报错,缺一个填一个,最终不知道少啥依赖,很苦恼,最终发现可以用这种springboot的这种方式导入,非常轻松。
由于dubbo是面向接口的RPC调用框架需要一个接口来为服务暴漏使用,该接口会响应传入的信息,下面是service的编写
package com.my.echo.api;
public interface EchoService {
String echo(String message);
}
二、xml方式
EchoServiceImpl的编写
package com.my.server.impl;
import com.my.echo.api.EchoService;
import java.text.SimpleDateFormat;
import java.util.Date;
public class EchoServiceImpl implements EchoService {
@Override
public String echo(String message) {
String now = new SimpleDateFormat("HH::mm::ss").format(new Date());
System.out.println("[" + now + "] hello" + message );
return message;
}
}
服务器xml的编写
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 服务提供方应用名称, 方便用于依赖跟踪 -->
<dubbo:application name="echo-provider"/>
<!-- 使用本地zookeeper作为注册中心 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 只用Dubbo协议并且指定监听端口 20880 -->
<dubbo:protocol name="dubbo" port="20880"/>
<!-- 通过xml方式配置为bean, 让spring托管和实例化 -->
<bean id="echoService" class="com.my.server.impl.EchoServiceImpl"/>
<!-- 声明服务暴露的接口,并暴露服务 -->
<dubbo:service interface="com.my.echo.api.EchoService" ref="echoService"/>
</beans>
服务器的编写
package com.my.server;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class EchoProvider {
public static void main(String[] args) throws IOException {
// 1.读取暴露配置的文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/echo-provider.xml"});
// 2.启动spring容器并暴露服务
context.start();
System.in.read();
}
}
客户端xml的编写
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 服务消费方应用名称, 方便用于依赖跟踪 -->
<dubbo:application name="echo-consumer"/>
<!-- 使用本地zookeeper作为注册中心 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 指定要消费的服务 -->
<dubbo:reference id="echoService" check="false" interface="com.my.echo.api.EchoService"/>
</beans>
服务器的编写
package com.my.client;
import com.my.echo.api.EchoService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class EchoConsumer {
public static void main(String[] args) {
//加载配置
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/echo-consumer.xml"});
context.start();;
//获取消费代理
EchoService echoService = (EchoService) context.getBean("echoService");
//调用远程方法
String status = echoService.echo("Hello World!");
System.out.println("echo result: " + status);
}
}
二、基于注解实现
通过xml配置,是比较常见的方式,而dubbo可以通过注解方式实现,这样可能会耦合一些,但是,对于代码的重构比较便利。
注解方式也需要EchoServiceImpl,代码与上节一样,不过多赘述。
配置类的编写
package com.my.echo.config;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableDubbo(scanBasePackages = {"com.my.echo.api"})//扫描服务所在的包
public class ProviderConfig {
@Bean
public ProviderConfig providerConfig(){
return new ProviderConfig();
}
@Bean
public ApplicationConfig applicationConfig(){
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("echo-annotation-provider");
return applicationConfig;
}
@Bean
public RegistryConfig registryConfig(){
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setProtocol("zookeeper");
registryConfig.setAddress("localhost");
registryConfig.setPort(2181);
return registryConfig;
}
@Bean
public ProtocolConfig protocolConfig(){
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName("dubbo");
protocolConfig.setPort(20880);
return protocolConfig;
}
}
服务器的编写
package com.my.echo;
import com.my.echo.config.ProviderConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.io.IOException;
public class EchoProvider {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfig.class);
context.start();
System.in.read();
}
}
客户端配置类如下
package com.my.echo.config;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableDubbo(scanBasePackages = {"com.my.echo.api"})
@ComponentScan(value = {"com.my.echo.api"})
public class ConsumerConfig {
@Bean
public ApplicationConfig applicationConfig(){
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("echo-annotation-consumer");
return applicationConfig;
}
@Bean
public ConsumerConfig consumerConfig(){
return new ConsumerConfig();
}
@Bean
public RegistryConfig registryConfig(){
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setProtocol("zookeeper");
registryConfig.setAddress("localhost");
registryConfig.setPort(2181);
return registryConfig;
}
}
客户端的编写如下
package com.my.echo;
import com.my.echo.api.EchoService;
import com.my.echo.config.ConsumerConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class EchoConsumer {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfig.class);
context.start();
EchoService echoService = (EchoService) context.getBean(EchoService.class);
String result = echoService.echo("Hello World!");
System.out.println("echo result:" + result);
}
}
三、基于API方式
采用API方式是最灵活的方式,可以与第三方框架集成。通过API方式是最简洁的。
服务器的代码如下
package com.my.echo;
import com.my.echo.api.EchoService;
import com.my.server.impl.EchoServiceImpl;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
public class EchoProvider {
public static void main(String[] args) {
ServiceConfig<EchoService> service = new ServiceConfig<>();
service.setApplication(new ApplicationConfig("java-echo-provider"));//给服务命名
service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));//创建注册中心,并指定协议,IP,端口号
service.setInterface(EchoService.class);//指定服务暴漏的接口
service.setRef(new EchoServiceImpl());//指定真实服务对象
service.export();//暴露服务
System.out.println("java-echo-provider is ruuning");
}
}
客户端代码如下
package com.my.echo;
import com.my.echo.api.EchoService;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
public class EchoConsumer {
public static void main(String[] args) {
ReferenceConfig<EchoService> reference = new ReferenceConfig<>();
reference.setApplication(new ApplicationConfig("java-consumer"));//设置消费方应用名称
reference.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
reference.setInterface(EchoService.class);//指定消费的接口
EchoService service = reference.get();//创建远程连接并做动态代理转换
String message = service.echo("Hello World!" );
System.out.println(message);
}
}