一、Dubbo概念介绍
1.1、Dubbo是什么?
Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbo这样的分布式服务框架的需求,并且本质上是个服务调用的东东,说白了就是个远程服务调用的分布式框架
其核心部分包含:
1》远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。
2》集群容错: 提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
3》自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
1.2. Dubbo能做什么?
1.透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
2.软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
3. 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
1.3. dubbo的架构
dubbo架构图如下所示:
节点角色说明:
Provider: 暴露服务的服务提供方。 (服务提供者在启动时,向注册中心注册自己提供的服务。)
Consumer: 调用远程服务的服务消费方。 (服务消费者在启动时,向注册中心订阅自己所需的服务。 )
Registry: 服务注册与发现的注册中心。(注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。)
Monitor: 统计服务的调用次调和调用时间的监控中心。 (服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。)
Container: 服务运行容器。( 服务容器负责启动,加载,运行服务提供者。)
对于这些角色来说,其他都还好,Monitor可能猿友们前期使用会把它忽略,但是后期会发现它的作用十分明显哦,如服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?为了解决这个问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。
二、前期准备
2.1、下载Zookeeper-3.3.6 :
https://pan.baidu.com/s/1QUDSlb185PP0gpwbAv4H5w
下载Apache-maven-3.3.9 :
https://pan.baidu.com/s/1i5eXbXOxxBLOKtYkRII5Jw
下载settings.xml :
https://pan.baidu.com/s/1enBc069Gn5jiCt7G4VJVVQ
下载dubbo.xsd :
https://pan.baidu.com/s/19egh9YPcsk0JDRSIlvJJ1w
2.2、配置环境变量
2.2.1、在Zookeeper的根目录下新建一个文件夹dataTmp,我的对应路径为:D:\zookeeper-3.3.6\dataTmp
2.2.2、修改conf文件夹下的 zoo.cfg
2.2.3、在环境变量中添加ZOOKEEPER_HOME 并在path中追加 ;%ZOOKEEPER_HOME%/bin;%ZOOKEEPER_HOME%/conf;
2.2.4、在环境变量中添加MAVEN_HOME 并在path中追加
;%MAVEN_HOME%\bin;
2.2.5、在E盘新建文件夹tools 将dubbo.xsd 和 settings.xml 放进去,后面会用到
三、注册中心、消费者、提供者搭建实例
3.1、Zookeeper的搭建
3.2、配置生产者 (Mybatis+datasource+redis)
3.2.1、创建base项目如下:
3.2.2、maven 配置settings.xml 步骤如下:
Window-------Preferences--------Maven-------User Settings 选择GlobalSettings和UserSettings 然后Apply
3.2.3、将maven工程转换成web工程,步骤如下:
右击工程属性,找到Project Facets,选择Dynamic Web Module,3.0
点击apply。这样把这个maven工程转换成了web工程。
3.2.4、配置dubbo本地catalog文件
由于阿里已经不再维护dubbo,原dubbo xml配置地址失效,在编译时dubbo-provider.xml可能会报错,该问题可以通过如下方式解决:下载dubbo.xsd(附件中有)并在eclipse->window->perferences->XML Catalog设置
其中key与配置文件相同为http://code.alibabatech.com/schema/dubbo/dubbo.xsd
3.2.5、修改pom.xml 如下:
<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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zx</groupId>
<artifactId>base</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>base</name>
<url>http://maven.apache.org</url>
<description>Dubbo分布式项目平台</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
</parent>
<dependencies>
<!-- ====================================spring boot==================================== -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<!-- ====================================AOP==================================== -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- ====================================Junit单元测试==================================== -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.4.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- ===============================Dubbo + Zookeeper==================================== -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.8.4</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.2</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- ===============================mysql==================================== -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- ===============================druid连接池==================================== -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.21</version>
</dependency>
<!-- ===============================fastjson json转对象(JsonObject)==================================== -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ===============================dom4j读写Xml==================================== -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!-- ====================== javassist 对 java字节码处理 为JBoss实现动态"AOP"框架。======================== -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
<!-- ===============================commons==================================== -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.1</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<!-- ===============================jedis 缓存==================================== -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
<!-- ===============================mybatis==================================== -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</project>
3.2.6、创建Application.java 和 SpringUtil.java
Application.java
package com.zx.base;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ImportResource;
@SpringBootApplication(exclude = MybatisAutoConfiguration.class)
//@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ImportResource(locations = "classpath*:/spring/applicationContext.xml")
public class Application extends SpringBootServletInitializer implements EmbeddedServletContainerCustomizer{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
//设置启动端口
container.setPort(8081);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
SpringUtil.java
package com.zx.base.rpc.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
/**
* SpringUtil类
*/
public final class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static Object get(String name) {
return applicationContext.getBean(name);
}
public static <T> T get(Class<T> cl) {
return applicationContext.getBean(cl);
}
public static void sendEvent(ApplicationEvent event) {
applicationContext.publishEvent(event);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.applicationContext = applicationContext;
}
}
3.2.7、在src/main/resources 下创建spring文件夹 创建applicationContext.xml (和刚才的Application.java中的locations对应)
创建logback-spring.xml (springboot启动时会自动加载)
applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 根据环境变量加载不同配置文件 运行时请注意在环境变量中配置-DenvTarget=local-->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/config/system-#{systemProperties['envTarget']}.properties
</value>
</list>
</property>
</bean>
<bean class="com.zx.base.rpc.util.SpringUtil" />
</beans>
logback-spring.xml
<!-- spring boot 默认会加载该文件 -->
<configuration debug="true" scan="true" scanPeriod="5 seconds">
<contextName>base</contextName>
<!-- 默认为local -->
<include resource="config/logback-${envTarget:-local}.xml" />
</configuration>
3.2.8、在src/main/resources 下新建config文件夹,创建logback配置文件
与logback-spring.xml 中的config/logback-${envTarget:-local}.xml 对应
logback-local.xml
<included>
<property name="LOG_PATH" value="${catalina.home:-.}/logs" />
<appender name="ROLLINGFILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/base.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/base.log.%d{yyyy-MM-dd}
</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<Pattern>%date{yyyy-MM-dd HH:mm:ss} %logger %level - %msg%n</Pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>%date{yyyy-MM-dd HH:mm:ss} %logger %level - %msg%n</Pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="ROLLINGFILE" />
</root>
</included>
system-local.properties.xml (这里配置系统参数,添加Zookeeper地址和Dubbo地址,数据源,redis地址)
#DUBBO CONFIG
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.monitor.address=dubbo://127.0.0.1:7070/com.alibaba.dubbo.monitor.MonitorService
#WRITE DB CONFIG
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl.write=jdbc:mysql://123.1.456.789:3306/live
jdbc.username.write=zx
jdbc.password.write=123456
#READ DB CONFIG
jdbc.jdbcUrl.read1=jdbc:mysql://123.1.456.789:3306/live
jdbc.username.read1=zx
jdbc.password.read1=123456
#REDIS CONFIG
redis.host=http://server1:zx@10.1.88.24:6379/0
3.2.9、配置Dubbo
在spring文件夹下创建dubbo-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" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd
http://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="base" owner="zx"/>
<!-- <dubbo:provider protocol="dubbo" port="20881"/> -->
<dubbo:protocol name="dubbo" port="20881" />
<!-- zookeeper注册中心 -->
<dubbo:registry address="${dubbo.registry.address}"/>
<!-- 配置监控的服务地址和IP -->
<dubbo:monitor address="${dubbo.monitor.address}" />
<!-- 配置导出文件大小上限 -->
<dubbo:protocol payload="11000000"></dubbo:protocol>
</beans>
在 applicationContext.xml中 追加
<!-- dubbo配置 -->
<import resource="dubbo-provider.xml"/>
3.2.10、 创建包和类,下面我的结构图
com.zx.base 下放的springboot启动类
com.zx.base.api.model.manager 下放的表实体类(generator逆向生成的)
com.zx.base.api.service.manager 下放的是service层接口
com.zx.base.api.vo 下放的是分页实体类
com.zx.base.prc.dbrw 下放的是数据源相关的实体类
com.zx.base.rpc.dao.manager 下放的是表Mapper (generator逆向生成的)
com.zx.base.rpc.service.manager 下放的是Service接口实现类
com.zx.base.rpc.util 下放的是各种工具类
ITestService.java
package com.zx.base.api.service.manager;
public interface ITestService {
public String getName();
}
Page.java
package com.zx.base.api.vo;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
public class Page implements Serializable{
private static final long serialVersionUID = -7510688937825278196L;
private int showCount; // 每页显示记录数
private int totalPage; // 总页数
private int totalResult; // 总记录数
private int currentPage; // 当前页
private int currentResult; // 当前记录起始索引
private int currentPageForApp; // 当前页 app用
private int currentResultForApp; // 当前记录起始索引 app用
private boolean entityOrField; // true:需要分页的地方,传入的参数就是Page实体;false:需要分页的地方,传入的参数所代表的实体拥有Page属性
private String pageStr; // 最终页面显示的底部翻页导航,详细见:getPageStr();
private String pageHtml;//一对多分页
private boolean export;
private String isSearch;
public String getIsSearch() {
return isSearch;
}
public void setIsSearch(String isSearch) {
this.isSearch = isSearch;
}
public boolean isExport() {
return export;
}
public void setExport(boolean export) {
this.export = export;
}
public Page() {
this.showCount = 15;
}
public int getTotalPage() {
if (totalResult % showCount == 0)
totalPage = totalResult / showCount;
else
totalPage = totalResult / showCount + 1;
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getTotalResult() {
return totalResult;
}
public void setTotalResult(int totalResult) {
this.totalResult = totalResult;
}
public int getPageNum() {
return currentPage;
}
public int getCurrentPage() {
if (currentPage <= 0)
currentPage = 1;
if (currentPage > getTotalPage())
currentPage = getTotalPage