基于spring-cloud相关技术整合,实现接口调用、服务容错、动态路由配置等

来源:互联网 发布:维金斯马刺数据 编辑:程序博客网 时间:2024/06/05 19:38

准备工作

创建数据库

CREATE DATABASE garlic;

创建数据库表

CREATE TABLE sys_user(    user_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT        PRIMARY KEY,    username VARCHAR(20) NOT NULL,    password VARCHAR(32) NOT NULL,    salt VARCHAR(32) NULL,    realname VARCHAR(20) NULL,    avatar VARCHAR(150) NULL,    phone VARCHAR(20) NULL,    email VARCHAR(50) NULL,    sex TINYINT NULL,    locked TINYINT NULL,    ctime BIGINT NULL);

创建maven工程,pom.xml

所有应用实例作为garlic-parent的子module存在,garlic-parent的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>    <groupId>com.garlic</groupId>    <artifactId>garlic-parent</artifactId>    <version>0.0.1-SNAPSHOT</version>    <modules>        <module>garlic-config-server</module>        <module>garlic-user-provider</module>        <module>garlic-user-consumer</module>        <module>garlic-eureka-server</module>        <module>garlic-zuul</module>        <module>garlic-common</module>        <module>garlic-user-api</module>        <module>garlic-web</module>        <module>garlic-zookeeper-server</module>        <module>garlic-kafka</module>        <module>garlic-rabbitmq</module>        <module>garlic-zipkin</module>    </modules>    <packaging>pom</packaging>    <name>garlic-parent</name>    <description>Demo project for Spring Boot</description>    <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>1.5.8.RELEASE</version>        <relativePath/> <!-- lookup parent from repository -->    </parent>    <properties>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>        <java.version>1.8</java.version>        <spring-cloud.version>Dalston.SR4</spring-cloud.version>        <org.mybatis.version>3.4.5</org.mybatis.version>        <org.mybatis.generator.version>1.3.5</org.mybatis.generator.version>        <com.github.pagehelper.version>5.0.0</com.github.pagehelper.version>        <com.fasterxml.jackson.core.version>2.9.1</com.fasterxml.jackson.core.version>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-aop</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-actuator</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-config</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-eureka</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-eureka-server</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-hystrix</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-zuul</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-feign</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-stream-binder-kafka</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>        <dependency>            <groupId>org.mybatis.generator</groupId>            <artifactId>mybatis-generator</artifactId>            <version>${org.mybatis.generator.version}</version>        </dependency>        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-core</artifactId>            <version>${com.fasterxml.jackson.core.version}</version>        </dependency>        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-databind</artifactId>            <version>${com.fasterxml.jackson.core.version}</version>        </dependency>        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-annotations</artifactId>            <version>${com.fasterxml.jackson.core.version}</version>        </dependency>    </dependencies>    <dependencyManagement>        <dependencies>            <dependency>                <groupId>org.springframework.cloud</groupId>                <artifactId>spring-cloud-dependencies</artifactId>                <version>${spring-cloud.version}</version>                <type>pom</type>                <scope>import</scope>            </dependency>        </dependencies>    </dependencyManagement>    <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>            </plugin>            <plugin>                <groupId>org.mybatis.generator</groupId>                <artifactId>mybatis-generator-maven-plugin</artifactId>                <version>${org.mybatis.generator.version}</version>                <configuration>                    <configurationFile>src/main/resources/generator-config.xml</configurationFile>                    <verbose>true</verbose>                    <overwrite>true</overwrite>                </configuration>                <executions>                    <execution>                        <id>Generate MyBatis Artifacts</id>                        <goals>                            <goal>generate</goal>                        </goals>                    </execution>                </executions>                <dependencies>                    <dependency>                        <groupId>org.mybatis.generator</groupId>                        <artifactId>mybatis-generator-core</artifactId>                        <version>${org.mybatis.generator.version}</version>                    </dependency>                </dependencies>            </plugin>        </plugins>    </build></project>

各实例端口参考:

garlic-eureka-server:10000 (实现高可用,分配端口1000010001,相互赋值)

garlic-config-server:8090 (配置中心,基于git的实现)

garlic-user-provider:9090(服务提供者,实现高可用,分配端口90909091

garlic-user-consumer:8080 (服务消费方)

garlic-zuul:7080 (Api网关,依赖config-server,实现动态路由)

garlic-zipkin: 9999 (监控,包括链路跟踪及日志查看,使用sleuth进行上报)

整合Eureka Server

maven依赖

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-eureka-server</artifactId></dependency>

激活Eureka

package com.garlic;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;/** * 服务注册与服务发现启动类 * * @author sam.liu * @create 2017-11-09 10:52 * @contact 563750241 * @email 563750241@qq.com */@SpringBootApplication@EnableEurekaServerpublic class GarlicEurekaServerApplication {    public static void main(String[] args) {        SpringApplication.run(GarlicEurekaServerApplication.class, args);    }}

application.properties

Eureka Server的高可用,是通过相互注册,信息复制的方式来实现,所以额外增加了application-master.propertiesapplication-slave.properties两个properties文件。

application.properties
# 配置应用名称spring.application.name=garlic-eureka-server# 配置服务端口server.port=10000# 关闭相互注册功能,如果实现高可用则需要开启eureka.client.register-with-eureka=trueeureka.client.fetch-registry=true# 关闭安全控制management.security.enabled=false# 默认启用master, 通过切换不同的profile来分别启动master与slavespring.profiles.active=slave
application-master.properties
# 配置服务端口server.port=10000# 配置注册中心,实现服务端的高可用,相互复制eureka.client.service-url.defaultZone=http://localhost:10001/eureka
application-slave.properties
# 配置服务端口server.port=10001# 配置注册中心,实现服务端的高可用,相互复制eureka.client.service-url.defaultZone=http://localhost:10000/eureka

整合Config Server

maven依赖

<dependency>      <groupId>org.springframework.cloud</groupId>      <artifactId>spring-cloud-config-server</artifactId></dependency>

激活Config Server

package com.garlic;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.config.server.EnableConfigServer;/** * 配置中心启动类 * * @author sam.liu * @create 2017-11-09 10:55 * @contact 563750241 * @email 563750241@qq.com */@SpringBootApplication@EnableConfigServer@EnableDiscoveryClientpublic class GarlicConfigServerApplication {    public static void main(String[] args) {        SpringApplication.run(GarlicConfigServerApplication.class, args);    }}

application.properties

# 配置应用名称spring.application.name=garlic-config-server# 关闭安全控制management.security.enabled=false# 配置服务端口server.port=8090# 配置git服务器# git 仓库地址spring.cloud.config.server.git.uri=*****************# git 仓库用户名spring.cloud.config.server.git.username=*********# git 仓库用户密码spring.cloud.config.server.git.password=******# 配置eureka服务注册中心eureka.client.service-url.defaultZone=http://localhost:10000/eureka,http://localhost:10001/eureka

配置中心基于git管理,此处主要用于profile的管理,比如数据库开发、测试、发布环境的区分,主要用于provider。同时用于动态路由的配置,主要用于zuul

整合Zipkin

Zipkin主要用于完整链路跟踪、日志查看等,Zipkin可以通过http被动收集日志或kafka主动收集日志两种方式,本实例中使用kafka主动收集日志的方式,所以需要引用spring-cloud-stream相关依赖,在启动Zipkin时,优先启动zookeeperkafka

增加依赖

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-sleuth-zipkin-stream</artifactId></dependency><dependency>    <groupId>io.zipkin.java</groupId>    <artifactId>zipkin-autoconfigure-ui</artifactId></dependency><dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-stream-binder-kafka</artifactId></dependency>

激活Zipkin

package com.garlic;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.sleuth.zipkin.stream.EnableZipkinStreamServer;/** * 服务监控 * * @author sam.liu * @create 2017-11-20 09:46 * @contact 563750241 * @email 563750241@qq.com */@SpringBootApplication@EnableZipkinStreamServerpublic class GarlicZipkinApplication {    public static void main(String[] args) {        SpringApplication.run(GarlicZipkinApplication.class, args);    }}

application.properties

## 配置应用实例名称spring.application.name=garlic-zipkin## 配置应用服务端口server.port=9999

本实例中,服务提供方、服务消费方与API网关需要上报日志,所以需要增加相关依赖

<dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-sleuth-zipkin-stream</artifactId></dependency><dependency>     <groupId>io.zipkin.java</groupId>     <artifactId>zipkin-autoconfigure-ui</artifactId></dependency><dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-stream-binder-kafka</artifactId></dependency>

服务提供方

本实例中,服务提供方为garlic-user-provider,数据持久层使用mybatis,当然也可使用hibernateJPA

此处涉及mybatis-generator的使用,自动生成mapper.xmlinterfacedomain实体相关信息,mybatis-generator的使用请参考mybatis系列之mybatis-generator的使用

如果需要在本实例中,使用mybatis-generator,直接运行

mvn mybatis-generator:generate 

maven依赖

        <dependency>            <groupId>org.mybatis</groupId>            <artifactId>mybatis</artifactId>            <version>${org.mybatis.version}</version>        </dependency>        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>        </dependency>        <dependency>            <groupId>com.github.pagehelper</groupId>            <artifactId>pagehelper-spring-boot-starter</artifactId>            <version>${com.github.pagehelper.version}</version>        </dependency>        <dependency>            <groupId>org.mybatis.spring.boot</groupId>            <artifactId>mybatis-spring-boot-starter</artifactId>            <version>1.3.1</version>        </dependency>        <dependency>            <groupId>com.garlic</groupId>            <artifactId>garlic-user-api</artifactId>            <version>${project.version}</version>        </dependency>        <!-- 添加 sleuth Stream 收集方式 -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-sleuth-stream</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-sleuth</artifactId>        </dependency>        <!-- Kafka Binder -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-stream-binder-kafka</artifactId>        </dependency>

应用入口GarlicUserProviderApplication

package com.garlic;import com.garlic.service.UserService;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.context.annotation.EnableAspectJAutoProxy;/** * {@link UserService} 用户服务,服务提供方启动类 * * @author sam.liu * @create 2017-11-09 11:00 * @contact 563750241 * @email 563750241@qq.com */@SpringBootApplication@EnableDiscoveryClient@MapperScan(basePackages = "com.garlic.mapper")@EnableAspectJAutoProxy(proxyTargetClass = true)public class GarlicUserProviderApplication {    public static void main(String[] args) {        SpringApplication.run(GarlicUserProviderApplication.class, args);    }}

包括激活AOP、配置mybatis的扫描包、激活DiscoveryClient

UserController

package com.garlic.controller;import com.garlic.domain.User;import com.garlic.domain.UserExample;import com.garlic.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.MediaType;import org.springframework.web.bind.annotation.*;import java.util.List;/** * {@link UserService} 用户服务,提供Rest Api {@link RestController} * * @author sam.liu * @create 2017-11-09 11:16 * @contact 563750241 * @email 563750241@qq.com */@RestController@RequestMapping(value = "/users")public class UserController {    private final UserService userService;    @Autowired    public UserController(UserService userService) {        this.userService = userService;    }    @GetMapping    public List<User> find(@RequestParam(defaultValue = "0") Integer offset,                           @RequestParam(defaultValue = "10") Integer limit) throws InterruptedException {        UserExample example = new UserExample();        return this.userService.find(offset, limit);    }    @GetMapping("/{id}")    public User find(@PathVariable("id") Integer id) {        return this.userService.find(id);    }}

domain及mapper代码部分,请参考项目git地址

application.properties

# 配置应用名称spring.application.name=garlic-user-provider# 配置服务端口server.port=9090# 关闭安全控制management.security.enabled=false# 配置eureka服务注册中心eureka.client.service-url.defaultZone=http://localhost:10000/eureka,http://localhost:10001/eureka# 配置数据库相关,配置来自于Config Serverspring.datasource.driver-class-name=${jdbc.driver}spring.datasource.url=${jdbc.url}spring.datasource.username=${jdbc.username}spring.datasource.password=${jdbc.password}# 配置mybatis相关## 配置实体包路径mybatis.type-aliases-package=com.garlic.domain## 配置mapper.xml文件路径mybatis.mapper-locations=classpath*:mapper/*.xml## 打印SQLmybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl## 分页相关配置,使用com.github.pagehelperpagehelper.helper-dialect=mysql#默认为false, 该参数对RowBounds作为分页参数时有效, 当参数设置为true时, offset参数在RowBounds用于pageNumpagehelper.offset-as-page-num=true#默认为false, 该参数设置为true时, PageHelper将执行count查询pagehelper.row-bounds-with-count=true#默认为false, 该参数设置为true时,如果pageSize=0 或 RowBounds.Limit=0时,将查询出全部结果(相当于未执行分页查询,但是返回的结果类型仍然是Page)pagehelper.page-size-zero=false#合理化分页参数,默认值为false,该参数设置为true时,pageNum<0 将查询第一页,PageNum > pages(即超过总页数) 将查询最后一页pagehelper.reasonable=true#为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值#默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。pagehelper.params=pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero

bootstrap.properties

# 配置eureka服务注册中心eureka.client.service-url.defaultZone=http://localhost:10000/eureka,http://localhost:10001/eureka### bootstrap 上下文配置# 配置客户端应用名称: garlicspring.cloud.config.name = garlic# profile 是激活配置spring.cloud.config.profile = prod# label 在Git中指的分支名称spring.cloud.config.label = master# 采用 Discovery client 连接方式,避免强依赖,根据配置中心serviceId配置依赖,在配置中心更换IP之后仍然正常## 激活 discovery 连接配置项的方式spring.cloud.config.discovery.enabled=true## 配置 config server 应用名称spring.cloud.config.discovery.serviceId=garlic-config-server

数据库配置信息

数据库配置信息存储在git中,从Config Server中获取

jdbc.url = jdbc:mysql://localhost:3306/garlic?useUnicode=true&characterEncoding=utf8jdbc.driver=com.mysql.jdbc.Driverjdbc.username=rootjdbc.password=123456

服务消费方

maven依赖

        <dependency>            <groupId>com.garlic</groupId>            <artifactId>garlic-user-api</artifactId>            <version>${project.version}</version>        </dependency>        <!-- 添加 sleuth Stream 收集方式 -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-sleuth-stream</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-sleuth</artifactId>        </dependency>        <!-- Kafka Binder -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-stream-binder-kafka</artifactId>        </dependency>

应用入口GarlicUserConsumerApplication

package com.garlic;import com.garlic.service.UserServiceProxy;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.netflix.feign.EnableFeignClients;import org.springframework.cloud.netflix.hystrix.EnableHystrix;import org.springframework.context.annotation.EnableAspectJAutoProxy;/** * {@link UserServiceProxy} 用户服务,服务消费方启动类 * * @author sam.liu * @create 2017-11-09 10:57 * @contact 563750241 * @email 563750241@qq.com */@SpringBootApplication@EnableDiscoveryClient@EnableFeignClients@EnableHystrix@EnableAspectJAutoProxy(proxyTargetClass = true)public class GarlicUserConsumerApplication {    public static void main(String[] args) {        SpringApplication.run(GarlicUserConsumerApplication.class, args);    }}

application.properties

# 配置应用名称spring.application.name=garlic-user-consumer# 配置服务端口server.port=8080# 关闭安全控制management.security.enabled=false# 配置eureka服务注册中心eureka.client.service-url.defaultZone=http://localhost:10000/eureka,http://localhost:10001/eureka# 启用feign的熔断机制feign.hystrix.enabled=true

API网关(Zuul)

maven依赖

<!-- 添加 sleuth Stream 收集方式 -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-sleuth-stream</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-sleuth</artifactId>        </dependency>        <!-- Kafka Binder -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-stream-binder-kafka</artifactId>        </dependency>

激活Zuul

package com.garlic;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.netflix.zuul.EnableZuulProxy;/** * Api 服务网关启动类 * * @author sam.liu * @create 2017-11-09 15:33 * @contact 563750241 * @email 563750241@qq.com */@SpringBootApplication@EnableDiscoveryClient@EnableZuulProxypublic class GarlicZuulApplication {    public static void main(String[] args) {        SpringApplication.run(GarlicZuulApplication.class, args);    }}

application.properties

# 配置应用名称spring.application.name=garlic-zuul# 配置服务端口server.port=7080# 关闭安全控制management.security.enabled=false# 配置路由(静态的方式配置路由,亦可通过动态的方式配置路由,必须借助于Config Server)#zuul.routes.users.path = /user-api/**#zuul.routes.users.serviceId=garlic-user-consumer

bootstrap.properties

# 配置eureka服务注册中心eureka.client.service-url.defaultZone=http://localhost:10000/eureka,http://localhost:10001/eureka### bootstrap 上下文配置# 配置客户端应用名称: zuul , 可当前应用是 spring-cloud-zuulspring.cloud.config.name = zuul# profile 是激活配置spring.cloud.config.profile = prod# label 在Git中指的分支名称spring.cloud.config.label = master# 采用 Discovery client 连接方式,避免强依赖,根据配置中心serviceId配置依赖,在配置中心更换IP之后仍然正常## 激活 discovery 连接配置项的方式spring.cloud.config.discovery.enabled=true## 配置 config server 应用名称spring.cloud.config.discovery.serviceId=garlic-config-server

路由配置

zuul.properties 存储在git中,通过Config Server加载

共包含zuul.propertieszuul-prod.propertieszuul-test.properties

zuul.properties
# 配置路由zuul.routes.users.path = /user-api/**zuul.routes.users.serviceId = garlic-user-consumer

zuul-prod.propertieszuul-tes.properties文件内容与zuul.properties相同

开发人员添加新的**consume**r实例之后,可以通过更改此配置文件,动态配置路由,例如:

新增garlic-order-consumer服务实例,则启动garlic-order-consumer之后,将配置文件修改为:

# 配置路由# 用户服务路由zuul.routes.users.path = /user-api/**zuul.routes.users.serviceId = garlic-user-consumer# 订单服务路由zuul.routes.orders.path = /order-api/**zuul.routes.orders.serviceId = garlic-order-consumer

调用接口端点zuul网关路由刷新,亦可通过启用@EnableScheduling配置定时任务自动刷新

服务首次启动,经常出现超时,这种现象是由于Ribboin Client创建的方式是lazy-create,解决方法参考Spring Cloud 服务第一次请求超时的优化

至此,整个Spring Cloud整合完成,欢迎指正!

阅读全文
0 0