注:springboot的版本号是2.x版本的。
provider的"pom"文件
<!-- springboot的父类依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--dubbo-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<!--zookeeper-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
<!--排除这个slf4j-log4j12-->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<!-- springboot整合mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.13</version>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- fork : 如果没有该项配置,这个devtools不会起作用,即应用不会restart -->
<fork>true</fork>
<!-- 支持静态文件热部署 -->
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
consumer的pom文件
<!-- springboot的父类依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--dubbo-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<!--zookeeper-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
<!--排除这个slf4j-log4j12-->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.44</version>
</dependency>
<!-- springboot整合mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!-- springboot热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.13</version>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- fork : 如果没有该项配置,这个devtools不会起作用,即应用不会restart -->
<fork>true</fork>
<!-- 支持静态文件热部署 -->
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
provider的启动类
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
//springboot的启动类
//指定项目要扫描的路径
@SpringBootApplication(scanBasePackages = {"com.my"})
//扫描"mybatis"的"mapper"包
@MapperScan("com.my.mapper")
//开启支持dubbo,并且指明dubbo要扫描的路径
@EnableDubbo(scanBasePackages = "com.my")
public class SpringApplications extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SpringApplications.class, args);
}
//为了打包springboot项目
@Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder builder) {
return builder.sources(this.getClass());
}
}
consumer的启动类
//springboot的启动类
@SpringBootApplication(scanBasePackages = {"com.my"})
@EnableDubbo(scanBasePackages = {"com.my"})
public class SpringApplications extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SpringApplications.class, args);
}
//为了打包springboot项目
@Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder builder) {
return builder.sources(this.getClass());
}
}
注:生产者和服务者的启动类都必须使用"@EnableDubbo"注解,并且都要指明dubbo要扫描的包,否则dubbo的注解就无法正常工作,就不能成功启动项目。
pojo实体类
public class SysUser implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String userName;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName == null ? null : userName.trim();
}
}
注:“pojo"实体类必须序列化(此处省略了"SysUser"的辅助类"SysUserExample”,但是项目中是有的)。
接口"SysUserService "
public interface SysUserService {
/**
* 分页查询
* @param page
* @param rows
* @return
*/
List<SysUser> findPageSysUser(Integer page,Integer rows);
/**
* 批量添加
* @param sysUserList
* @return
*/
List<SysUser> addSysUserList(List<SysUser> sysUserList);
}
接口实现类"SysUserServiceImpl "
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.PageHelper;
import com.my.mapper.SysUserMapper;
import com.my.pojo.SysUser;
import com.my.pojo.SysUserExample;
import com.my.service.SysUserService;
/**
* "@Service"是阿里的包(com.alibaba.dubbo.config.annotation.Service)
* 他不会将当前类注入到"spring"的容器中,他会将当期类当成一个服务,
* 发布到注册中心中(常指"zokeeper")。
* "version="1.0.0""指定服务的版本号,以示区别,
* "timeout=30000"指定超时时间,也可以在"application.properties"中
* 通过"dubbo.provider.timeout=30000"来统一指定。
* "protocol"指明dubbo使用的协议,默认使用"dubbo"协议
*
* "loadbalance"负载均衡(随机("random")、最小活跃数("leastactive")、
* 轮询("roundrobin"和哈希("consistenthash"))
*
* "consumer"(消费者)在引用时,必须指明该版本号,
* 否则无法正确引用。
* "@Component"代替"spring"的"@Service",
* 因为此处引用的是阿里的"@Service",如果没有"@Component",
* 则当前项目无法在其他地方引用。
*/
@Service(version="1.0.0")
@Component
public class SysUserServiceImpl implements SysUserService {
@Autowired
private SysUserMapper sysUserMapper;
@Override
public List<SysUser> findPageSysUser(Integer page, Integer rows) {
SysUserExample example = new SysUserExample();
if(!StringUtils.isEmpty(page) && !StringUtils.isEmpty(rows)){
PageHelper.startPage(page, rows);
}
List<SysUser> list = sysUserMapper.selectByExample(example);
if(list != null && list.size() > 0){
return list;
}else{
return null;
}
}
@Transactional
@Override
public List<SysUser> addSysUserList(List<SysUser> sysUserList) {
int count = 0;
for (SysUser sysUser : sysUserList) {
int result = sysUserMapper.insert(sysUser);
count += result;
}
if(count == sysUserList.size()){
return sysUserList;
}else{
int a = 1 / 0;
System.out.println(a);
return null;
}
}
}
注:"pojo"实体类(“SysUser”)和接口(“SysUserService” ),"provider"和"consumer"公用(完全一样),接口实现类"SysUserServiceImpl "只有"生产者或发布者(“provider”)"需要实现。
生产者的"controller"类
import java.util.List;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.dubbo.config.annotation.Reference;
import com.my.pojo.SysUser;
import com.my.service.SysUserService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
@RestController
@RequestMapping("/sys/user")
public class SysUserController {
/**
* "@Reference"是dubbo的注解,也是注入,他一般注入的是分布式的远程服务的对象,
*
* "version="1.0.0""表示注入生产者生成对应的版本的服务,只有生产者("provider")和
* 消费者("consumer")的版本号一致,分布式对象才能正确注入;
*
* "timeout = 30000"是服务请求的超时时间,也可以在"application.properties"中
* 通过"dubbo.consumer.timeout=30000"来统一指定。
*
* "check"默认为"true",当"check=true"时,在启动消费者(consumer),
* 消费者会先检查自己依赖的服务是否存在,如果服务不存在,
* 会抛出异常,阻止Spring初始化完成;当"check=false"时,
* 在启动消费者"consumer",消费者就不去检查自己依赖的服务是否存在,
* 此时消费者可以启动成功,但是不能调用生产者所提供的服务,
* 只有当生产者也成功启动后,才可以使用。
*
* "loadbalance"负载均衡(随机("random")、最小活跃数("leastactive")、
* 轮询("roundrobin"和哈希("consistenthash"))
*/
@Reference(version="1.0.0",timeout = 30000)
private SysUserService sysUserService;
@ApiOperation(value = "批量添加用户")
@ApiImplicitParam(name = "sysUserList", value = "用户集合", required = true, paramType = "body", dataType = "SysUser")
@RequestMapping(value = "/addSysUserList",method = RequestMethod.POST)
public List<SysUser> addSysUserList(@RequestBody List<SysUser> sysUserList){
List<SysUser> list = sysUserService.addSysUserList(sysUserList);
return list;
}
@ApiOperation(value = "分页查询用户")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "当前页码", required = false, paramType = "query", dataType = "Long"),
@ApiImplicitParam(name = "rows", value = "显示行数", required = false, paramType = "query", dataType = "Long")
})
@RequestMapping(value = "/findPageSysUser",method = RequestMethod.GET)
public List<SysUser> findPageSysUser(Integer page, Integer rows){
List<SysUser> list = sysUserService.findPageSysUser(page, rows);
return list;
}
}
基于配置类的方式
"配置类"就是将发布信息,编译成配置类的方式,指明生产者、消费者、注册中心和发布信息及其发布端口。
"provider"的配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.RegistryConfig;
@Configuration
public class ProviderConfig {
//创建ApplicationConfig
@Bean
public ApplicationConfig applicationConfig(){
ApplicationConfig config = new ApplicationConfig ();
//指明生产者的名称
config.setName("provider");
return config;
}
//创建注册中心
@Bean
public RegistryConfig registryConfig(){
RegistryConfig config = new RegistryConfig();
//指明注册中心的地址
config.setAddress("zookeeper://192.168.163.128:2181");
return config;
}
//指定服务发布的协议和端口
@Bean
public ProtocolConfig ProtocolConfig(){
ProtocolConfig config = new ProtocolConfig();
//指明协议名称
config.setName("dubbo");
//指定端口
config.setPort(54321);
return config;
}
}
"consumer"的配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.RegistryConfig;
@Configuration
public class ConsumerConfig {
//创建ApplicationConfig
@Bean
public ApplicationConfig applicationConfig(){
ApplicationConfig config = new ApplicationConfig ();
//指明消费者的名称
config.setName("consumer");
return config;
}
//根据注册中心
@Bean
public RegistryConfig registryConfig(){
RegistryConfig config = new RegistryConfig();
//指明注册中心的地址
config.setAddress("zookeeper://192.168.163.128:2181");
return config;
}
//指定服务发布的协议和端口
@Bean
public ProtocolConfig ProtocolConfig(){
ProtocolConfig config = new ProtocolConfig();
//指明协议名称
config.setName("dubbo");
//指定端口
config.setPort(54321);
return config;
}
}
注:生产者和消费者的"协议"必须保持一致,否则无法成功注入,并且这个暴露的端口必须在防火墙中开头,(这个暴露的端口是指,将生产者发布到那台服务器上,就是这台机器的该端口)。
基于配置文件的方式
配置文件是指,在"application.properties"中写明发布信息。
provider的"application.properties"
#dubbo配置信息
#dubbo的application名称必须写
dubbo.application.name=provider
#注册中心,必写
dubbo.registry.address=zookeeper://118.25.177.138:2181
#协议,必写
dubbo.protocol.name=dubbo
#暴露服务的端口,最大值为65535
dubbo.protocol.port=12345
#超时时间
dubbo.provider.timeout=30000
consumer的"application.properties"
#dubbo的配置信息
#dubbo的application名称必须写
dubbo.application.name=consumer
#注册中心,必写
dubbo.registry.address=zookeeper://118.25.177.138:2181
#协议,必写
dubbo.protocol.name=dubbo
#暴露服务的端口,最大值为65535
dubbo.protocol.port=12345
#超时时间
dubbo.consumer.timeout=30000
注:在启动时,必须先启动"provider",只有"provider"成功后,才能启动"consumer"。
生产者和消费者之间公用的实体类名"pojo",此处为"SysUser";接口名(“service”),此处为"SysUserService "的绝对路径必须完全一致,否则在进行rpc通信时会出现错误。
如果是接口名不一致,则发布的生产者在"dubbo-admin"中会显示找不到消费者,发布的消费者在"dubbo-admin"中会显示找不到发布者;如果是实体类名不一致,则即使实体类实现了"Serializable"接口,仍然会报出现实体类无法实现序列化的问题。