文章目录
Spring Boot - 集成Dubbo
说到分布式服务框架,国内开发同学可能很快就能联想到Spring Cloud和Dubbo,从搜索数据可以看到Dubbo因为阿里的原因在我们国内还是比较火热的,国外更多的可能还是使用Spring Cloud更多,随着Dubbo正式进入Apache孵化器,相信Dubbo在整个开发行业也会得到不错的支持。
对于Dubbo具体的相关内容我们这里就不做介绍,这里我们主要对Spring Boot集成Dubbo做一个简单的介绍。首先我们跟传统接入Dubbo一样,在项目结构上主要分为三部分:服务提供者、服务消费者、公共组件(由提供者实现、消费者调用),我们先搭建一个父项目方便管理,然后分别搭建
springboot-dubbo-ifc
、springboot-dubbo-provider
、springboot-dubbo-consumer
三个子项目分别负责以上三部分功能。
首先我们可以在github上看到阿里巴巴提供的dubbo-spring-boot-starter项目的开源地址,接下来的开发中我们就需要引入这个依赖进行开发GitHub - alibaba/dubbo-spring-boot-starter
1.springboot-dubbo-ifc(公共组件)
这个公共组件的作用主要就是提供出公共的接口方法,使提供者实现以及消费者调用解耦并且达到一致性,这里为了方便我们直接把数据库操作的实体类放在了这里,真正开发中建议这里无论是作为传参或者输出公用的实体类是数据经过转换的DTO对象,而不建议直接放置数据库操作对象,我们为了简单去集成dubbo所以不做这些转换操作。
1.1 公用接口
数据传输对象的具体代码我们这里就不展示,没有实际意义,根据大家自己业务来调整,这里我们主要创建了一个公用的接口,用于通过ID去查询具体数据,简单集成的话就这样简单的一步。
package com.springboot.service;
import com.springboot.repository.entity.BlogDictionary;
import java.util.List;
/** * @author hzk * @date 2018/12/19 */
public interface IDictionaryService {
BlogDictionary selectByPrimaryKey(Integer id);
}
2.springboot-dubbo-provider(服务提供者)
有了上面公用组件之后,那我们接下来就可以开发我们的服务提供者了,这里相关Dao层就不列出来,都是常规简单sql进行数据操作,和集成影响不大,使文章更加简洁易懂。
2.1 引入pom依赖
首先这里引入dubbo提供的dubbo-spring-boot-starter依赖是开发dubbo必不可少的,由于使用到了注册中心zookeeper和dubbo但是同样也需要spring-boot-starter-web起步依赖,中间可能会存在一个log冲突导致无法启动的问题,这里我们先简单处理一下,将spring boot中logback排除然后自己手动引入版本对应的log包,然后引入我们的公用组件。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springboot</groupId>
<artifactId>springboot-dubbo-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>springboot-dubbo-provider</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<log4j.version>1.2.17</log4j.version>
<log4j.remix.version>0.2.7</log4j.remix.version>
<slf4j.version>1.7.5</slf4j.version>
</properties>
<dependencies>
<!-- 由于dubbo以及zookeeper内部都引入了各自的日志jar包 容易发生冲突不好解决 所以可以我们自己手动加入对应匹配版本日志jar包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.lazyluke</groupId>
<artifactId>log4jdbc-remix</artifactId>
<version>${log4j.remix.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--Exception in thread "main" java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.Log4jLoggerFactory loaded from file:/G:/JavaTools/maven/repository/org/slf4j/slf4j-log4j12/1.7.25/slf4j-log4j12-1.7.25.jar). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.impl.Log4jLoggerFactory logback 和log4j冲突 需要去除logback依赖-->
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- dubbo接口项目依赖jar-->
<dependency>
<groupId>com.springboot</groupId>
<artifactId>springboot-dubbo-ifc</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 加载SpringBoot整合Dubbo起步依赖 -->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!-- zkclient -->
<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 jdbc驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- 打jar包插件可能需要用1.4.2.RELEASE 其他版本可能有问题-->
<!--<version>1.4.2.RELEASE</version>-->
</plugin>
</pluginManagement>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
</project>
2.2 配置文件
既然作为提供者,那么数据库的配置以及dubbo配置则不可或缺。
log4j.properties
log4j.rootLogger=INFO, stdout
# Console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
# 注释:d时间 p等级 c类 m信息 n换行 t线程
log4j.appender.stdout.layout.ConversionPattern=%5p %d{yyyy-MM-dd HH:mm:ss} [%t] [%m] [%c] %n
application.properties
这里dubbo的配置没有采取之前xml的方式,当然何种方式配置都是可以自己选择的,根据自己需要配置即可,这里的配置属性仅为简单启动配置,更多详细的大家自己查阅资料。
server.port=8080
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/blog?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
#Dubbo服务配置
spring.dubbo.application.name=springboot-dubbo-provider
spring.dubbo.registry.address=zookeeper://127.0.0.1:2181
#spring.dubbo.registries[0].address=zookeeper://127.0.0.1:2181
spring.dubbo.server=true
spring.dubbo.protocol.name=dubbo
spring.dubbo.protocol.port=20881
spring.dubbo.scan =com.springboot.service.impl
2.3 接口服务实现
之前使用dubbo我们通过xml形式配置了接口服务发布的各种属性绑定关系,这里我们采取Spring Boot更推荐的注解形式,注意的是这里需要利用dubbo提供的@Service注解去配置接口服务的发布属性,注意不要和Spring提供的@Service注解弄混淆,并且同时还是需要将该类通过Spring提供的@Service或者@Component去扫描到Spring容器中提供使用的。
这里配置的
@Service(version = "1.0",timeout = 10000)
就和我们之前利用xml配置的
<dubbo:service interface="com.springboot.service.IDictionaryService " ref="dictionaryServiceImpl " timeout="10000" version="1.0" />
作用是一致的,具体属性配置大家根据自己使用情况去了解。
DictionaryServiceImpl .java
package com.springboot.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.springboot.dao.read.BlogDictionaryMapper;
import com.springboot.repository.entity.BlogDictionary;
import com.springboot.service.IDictionaryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/** * Service注解为dubbo提供 作用与 <dubbo:service interface=... ref.../>一致 * @author hzk * @date 2018/12/24 */
@Component
@Service(version = "1.0",timeout = 10000)
public class DictionaryServiceImpl implements IDictionaryService {
@Autowired
private BlogDictionaryMapper blogDictionaryMapper_r;
@Override
public BlogDictionary selectByPrimaryKey(Integer id) {
return blogDictionaryMapper_r.selectByPrimaryKey(id);
}
}
2.4 入口类
通过上面这几步,Spring Boot集成Dubbo就基本实现了,接下来只需要在入口类上添加
@EnableDubboConfiguration
注解,在项目运行之后就会自动去扫描注册Dubbo相关的信息了,这里由于我们建的时候选择的是war包的项目,所以和之前稍有不同,jar以及war的不同启动的差异化这里就不介绍了。
SpringBootDubboProviderApplicationWar .java
package com.springboot;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
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;
/** * 继承SpringBootServletInitializer (打war) * EnableDubboConfigurati 开启dubbo功能 * @author hzk */
@SpringBootApplication
@MapperScan(basePackages = "com.springboot.dao")
@EnableDubboConfiguration
public class SpringBootDubboProviderApplicationWar extends SpringBootServletInitializer
{
public static void main( String[] args )
{
SpringApplication.run(SpringBootDubboProviderApplicationWar.class);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBootDubboProviderApplicationWar.class);
}
}
启动入口类,在zookeeper中可以查看到对应节点下存储了对应Dubbo接口服务的信息,即成功。
3.springboot-dubbo-consumer(服务消费者)
3.1 引入pom依赖
这里依赖大致和服务提供者一致,这是不需要数据库相关操作的依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springboot</groupId>
<artifactId>springboot-dubbo-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-dubbo-consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<log4j.version>1.2.17</log4j.version>
<log4j.remix.version>0.2.7</log4j.remix.version>
<slf4j.version>1.7.5</slf4j.version>
</properties>
<dependencies>
<!-- 由于dubbo以及zookeeper内部都引入了各自的日志jar包 容易发生冲突不好解决 所以可以我们自己手动加入对应匹配版本日志jar包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.lazyluke</groupId>
<artifactId>log4jdbc-remix</artifactId>
<version>${log4j.remix.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--Exception in thread "main" java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.Log4jLoggerFactory loaded from file:/G:/JavaTools/maven/repository/org/slf4j/slf4j-log4j12/1.7.25/slf4j-log4j12-1.7.25.jar). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.impl.Log4jLoggerFactory logback 和log4j冲突 需要去除logback依赖-->
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- dubbo接口项目依赖jar-->
<dependency>
<groupId>com.springboot</groupId>
<artifactId>springboot-dubbo-ifc</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 加载SpringBoot整合Dubbo起步依赖 -->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!-- zkclient -->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2 配置文件
log日志的配置文件和提供者一致即可,在调用dubbo的配置文件稍微有一点不同,由于我们是消费方,所以这里只需要知道服务注册的地址。
application.properties
#Dubbo 消费配置
spring.dubbo.application.name=springboot-dubbo-consumer
spring.dubbo.registry.address=zookeeper://127.0.0.1:2181
3.3 接口服务调用
Spring Boot调用接口服务也十分简单,通过
@Reference
注解就可以直接使用。
这里配置的@Reference(version = "1.0")
就和我们之前利用xml配置的
<dubbo:reference interface="com.springboot.service.IDictionaryService" id="dictionaryService" check="false" version="1.0" />
作用是一致的,具体属性配置大家根据自己使用情况去了解。
DictionaryController .java
package com.springboot.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.springboot.service.IDictionaryService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/** * @author hzk * @date 2018/12/25 */
@RestController
public class DictionaryController {
/** * <dubbo:reference group="" interface="" id="" check="false" version="1.0" /> */
@Reference(version = "1.0")
private IDictionaryService dictionaryService;
@GetMapping(value = "/dic/{id}")
public Object getDictionary(@PathVariable(name = "id") Integer id){
return dictionaryService.selectByPrimaryKey(id);
}
}
2.4 入口类
接下来同样只需要在入口类上添加
@EnableDubboConfiguration
注解即可,这里我们用了jar的方式,说明Spring Boot使用起来十分灵活。
SpringbootDubboConsumerApplication .java
package com.springboot;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubboConfiguration
public class SpringbootDubboConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDubboConsumerApplication.class, args);
}
}
启动入口类后,通过调用接口获取正确数据表明Spring Boot集成Dubbo已经完成了。