现状
团队现有框架是重度依赖dubbo,分层逻辑不清晰,导致开发模式有点重。开发一些非分布式小项目,如果使用统一的编码规范,依赖框架,就会导致被动依赖dubbo。这种开发模式,在小项目开发时,效率低下,成本过高。
解决方案
现考虑升级框架,对现有框架做拆分,以spring-boot-starter的方式,形成独立模块,单独依赖,并且可以大量简化较为繁重的xml配置。
由于框架中,最深度依赖的就是dubbo,所以首先针对rpc模块动刀,开发一个dubbo-spring-boot-starter。
实战
参照springboot的官方文档,starter项目分两个模块,starter和autoconfigure。
项目地址:https://github.com/coderzl/dubbo-spring-boot
dubbo-spring-boot
新建maven父工程,dubbo-spring-boot
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>
<groupId>cn.coderzl.dubbo</groupId>
<artifactId>dubbo-spring-boot</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>dubbo-spring-boot</name>
<description>dubbo for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modules>
<module>dubbo-spring-boot-autoconfigure</module>
<module>dubbo-spring-boot-starter</module>
<module>dubbo-api-spring-boot-test</module> <!-- test project -->
<module>dubbo-provider-spring-boot-test</module> <!-- test project -->
<module>dubbo-consumer-spring-boot-test</module> <!-- test project -->
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<project.model.version>1.0-SNAPSHOT</project.model.version>
<java.version>1.8</java.version>
<spring-boot.version>1.5.9.RELEASE</spring-boot.version>
<zookeeper.version>3.4.6</zookeeper.version>
<dubbo.version>2.5.7</dubbo.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
dubbo-spring-boot-autoconfigure
创建module dubbo-spring-boot-autoconfigure
pom.xml文件
<?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>cn.coderzl.dubbo</groupId>
<artifactId>dubbo-spring-boot</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>cn.coderzl.dubbo</groupId>
<artifactId>dubbo-spring-boot-autoconfigure</artifactId>
<version>${project.model.version}</version>
<packaging>jar</packaging>
<name>dubbo-spring-boot-autoconfigure</name>
<description>Dubbo Configure for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>zookeeper</artifactId>
<groupId>org.apache.zookeeper</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.4</version>
</dependency>
</dependencies>
</project>
- 属性对象
DubboProperties 装载初始自动配置的相关属性,下面的对象,只配置了我们项目中暂时用到到一些属性。。。
@ConfigurationProperties(prefix = DubboProperties.DUBBO_PREFIX)
public class DubboProperties {
public static final String DUBBO_PREFIX = "dubbo";
/** 消费者配置开关 默认关闭(暂未生效) */
private boolean consumerTrigger;
/** 生产者配置开关 默认关闭(暂未生效) */
private boolean providerTrigger;
/** applicationName */
private String applicationName;
/** 注册中心地址 */
private String registryAddress;
/** 启动时是否检查注册中心 */
private boolean registryCheck = false;
/** 协议 默认:dubbo */
private String protocol = "dubbo";
/** 端口 默认 20800 */
private int port = 20800;
/** HOST */
private String host;
/** dubbo 线程数, 默认 200 */
private int threads = 200;
/** 重试次数 默认不重试 */
private int retries = 0;
/** consumerCheck 默认不检查 */
private boolean consumerCheck = false;
/** 消费者过滤器 多个用,隔开 */
private String consumerFilter;
/** 提供者者过滤器 多个用,隔开 */
private String providerFilter;
/** providerCheck 默认不检查 */
private boolean providerCheck = false;
/** group */
private String group;
/** 超时时间 */
private int timeout;
//…………省略getter/setter
}
- DubboAutoConfiguration
配置了一些通用的基础config。
@Configuration
@EnableConfigurationProperties(DubboProperties.class)
public class DubboAutoConfiguration {
private static final Logger logger = LoggerFactory.getLogger(DubboAutoConfiguration.class);
@Autowired
private DubboProperties dubboProperties;
@PostConstruct
public void checkConfigFileExists(){
if (!StringUtils.hasText(dubboProperties.getRegistryAddress()) || !StringUtils.hasText(dubboProperties.getApplicationName())){
throw new IllegalArgumentException("RegistryAddress or ApplicationName is null");
}
}
@Bean
@ConditionalOnMissingBean
public ApplicationConfig getApplicationConfig(){
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName(dubboProperties.getApplicationName());
return applicationConfig;
}
@Bean
@ConditionalOnMissingBean
public RegistryConfig getRegistryConfig(){
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress(dubboProperties.getRegistryAddress());
registryConfig.setCheck(dubboProperties.isRegistryCheck());
return registryConfig;
}
@Bean
@ConditionalOnMissingBean
public ProtocolConfig getProtocolConfig(){
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName(dubboProperties.getProtocol());
protocolConfig.setHost(dubboProperties.getHost());
protocolConfig.setPort(dubboProperties.getPort());
return protocolConfig;
}
@Bean
@ConditionalOnMissingBean
public MonitorConfig getMonitorConfig(){
MonitorConfig monitorConfig = new MonitorConfig();
monitorConfig.setProtocol("registry");
return monitorConfig;
}
}
- DubboProviderAutoConfiguration
服务提供者端初始配置
/**
* <p> dubbo提供者自动配置 </p>
*
* @author coderzl
* @Title DubboProviderAutoConfiguration
* @date 2017/12/4 10:27
* @package cn.coderzl.dubbo.spring.boot.autoconfigure
*/
@Configuration
@EnableConfigurationProperties(DubboProperties.class)
@AutoConfigureAfter(DubboAutoConfiguration.class)
public class DubboProviderAutoConfiguration {
@Autowired
private DubboProperties dubboProperties;
@Bean
@ConditionalOnMissingBean
public ProviderConfig getProviderConfig(){
ProviderConfig providerConfig = new ProviderConfig();
providerConfig.setRetries(dubboProperties.getRetries());
providerConfig.setFilter(dubboProperties.getConsumerFilter());
providerConfig.setTimeout(dubboProperties.getTimeout());
providerConfig.setGroup(dubboProperties.getGroup());
return providerConfig;
}
}
- DubboConsumerAutoConfiguration
服务消费者端自动配置
/**
* <p> dubbo消费者自动配置 </p>
*
* @author coderzl
* @Title DubboConsumerAutoConfiguration
* @date 2017/12/4 10:26
* @package cn.coderzl.dubbo.spring.boot.autoconfigure
*/
@Configuration
@EnableConfigurationProperties(DubboProperties.class)
@AutoConfigureAfter(DubboAutoConfiguration.class)
public class DubboConsumerAutoConfiguration {
@Autowired
private DubboProperties dubboProperties;
@Bean
@ConditionalOnMissingBean
public ConsumerConfig getConsumerConfig(){
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setRetries(dubboProperties.getRetries());
consumerConfig.setTimeout(dubboProperties.getTimeout());
consumerConfig.setCheck(dubboProperties.isConsumerCheck());
consumerConfig.setGroup(dubboProperties.getGroup());
return consumerConfig;
}
}
- spring.factories
在META-INF目录下配置spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.coderzl.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration,\
cn.coderzl.dubbo.spring.boot.autoconfigure.DubboConsumerAutoConfiguration,\
cn.coderzl.dubbo.spring.boot.autoconfigure.DubboProviderAutoConfiguration
dubbo-spring-boot-starter
这是一个空项目
- 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>
<groupId>cn.coderzl.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${project.model.version}</version>
<name>dubbo-spring-boot-starter</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>cn.coderzl.dubbo</groupId>
<artifactId>dubbo-spring-boot</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>cn.coderzl.dubbo</groupId>
<artifactId>dubbo-spring-boot-autoconfigure</artifactId>
<version>${project.model.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
- spring.provides
在META-INF目录下创建spring.provides
provides: dubbo-spring-boot-autoconfigure