#spring-boot + spring-cloud
0.创建项目依赖
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.0.2.RELEASE</version>
</parent>
<groupId>com.hang</groupId>
<artifactId>hello-spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<description>工程依赖层</description>
<packaging>pom</packaging>
<!-- <name>hello-spring-cloud-dependencies</name>
<url>http://www.funtl.com</url>
<inceptionYear>2018-Now</inceptionYear>-->
<properties>
<!-- Environment Settings -->
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring Settings -->
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
<spring-cloud-zipkin.version>2.10.1</spring-cloud-zipkin.version>
<spring-cloud-admin.version>2.0.1</spring-cloud-admin.version>
</properties>
<!--工程依赖-->
<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>
<!--spring cloud begin-->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
<version>${spring-cloud-zipkin.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<version>${spring-cloud-zipkin.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>${spring-cloud-zipkin.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring-cloud-admin.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring-cloud-admin.version}</version>
</dependency>
<!--spring cloud end -->
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!-- Compiler 设定 JDK 插件, 版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<!-- 打包 jar 文件时,配置 manifest 文件,加入 lib 包的 jar 依赖 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
<executions>
<execution>
<configuration>
<archive>
<manifest>
<!-- Add directory entries -->
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
<!-- resource -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
<!-- install -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
</plugin>
<!-- clean -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
</plugin>
<!-- ant -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
<!-- dependency -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!-- Java Document Generate -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- YUI Compressor (CSS/JS压缩) -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<version>1.5.1</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>compress</goal>
</goals>
</execution>
</executions>
<configuration>
<encoding>UTF-8</encoding>
<jswarn>false</jswarn>
<nosuffix>true</nosuffix>
<linebreakpos>30000</linebreakpos>
<force>true</force>
<includes>
<include>**/*.js</include>
<include>**/*.css</include>
</includes>
<excludes>
<exclude>**/*.min.js</exclude>
<exclude>**/*.min.css</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<!-- 资源文件配置 -->
<resources>
<resource>
<directory>src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>aliyun-repos</id>
<name>Aliyun Repository</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>sonatype-repos</id>
<name>Sonatype Repository</name>
<url>https://oss.sonatype.org/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>sonatype-repos-s</id>
<name>Sonatype Repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>aliyun-repos</id>
<name>Aliyun Repository</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
##1.设置服务创建与发现
(eureka)
项目名:hello-spring-cloud-eureka
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>com.hang</groupId>
<artifactId>hello-spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>hello-spring-cloud-eureka</artifactId>
<description>服务注册与发现,使用spring-cloud的eureka项目</description>
<packaging>jar</packaging>
<!-- <name>hello-spring-cloud-eureka</name>
<url>http://www.funtl.com</url>
<inceptionYear>2018-Now</inceptionYear>-->
<dependencies>
<!-- Spring Boot Begin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot End -->
<!-- Spring Cloud Begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--项目跟踪依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<!--服务监控-->
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.hang.hello.spring.cloud.eureka.EurekaApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
application:
name: hello-spring-cloud-eureka
server:
port: 8762
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
1.5创建服务链式追踪
ZipKin 是一个开放源代码的分布式跟踪系统,由 Twitter 公司开源,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。它的理论模型来自于 Google Dapper 论文。
微服务架构是通过业务来划分服务的,使用 REST 调用。对外暴露的一个接口,可能需要很多个服务协同才能完成这个接口功能,如果链路上任何一个服务出现问题或者网络超时,都会形成导致接口调用失败。随着业务的不断扩张,服务之间互相调用会越来越复杂。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xdquHGec-1610092415201)(https://www.funtl.com/assets/2279594-dd72907e82f89fd6.png)]
随着服务的越来越多,对调用链的分析会越来越复杂。它们之间的调用关系也许如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5x1LlWoe-1610092415204)(https://www.funtl.com/assets/2279594-4b7d1b6abe595390.png)]
-
Span:基本工作单元,例如,在一个新建的 Span 中发送一个 RPC 等同于发送一个回应请求给 RPC,Span 通过一个 64 位 ID 唯一标识,Trace 以另一个 64 位 ID 表示。
-
Trace:一系列 Spans 组成的一个树状结构,例如,如果你正在运行一个分布式大数据工程,你可能需要创建一个 Trace。
-
Annotation:用来即使记录一个事件的存在,一些核心 Annotations 用来定义一个请求的开始和结束
-
cs:Client Sent,客户端发起一个请求,这个 Annotation 描述了这个 Span 的开始
-
sr:Server Received,服务端获得请求并准备开始处理它,如果将其 sr 减去 cs 时间戳便可得到网络延迟
-
ss:Server Sent 表明请求处理的完成(当请求返回客户端),如果 ss 减去 sr 时间戳便可得到服务端需要的处理请求时间
-
cr:Client Received 表明 Span 的结束,客户端成功接收到服务端的回复,如果 cr 减去 cs 时间戳便可得到客户端从服务端获取回复的所有所需时间
-
将 Span 和 Trace 在一个系统中使用 Zipkin 注解的过程图形化:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-35HG6jBC-1610092415206)(https://www.funtl.com/assets/2279594-4b865f2a2c271def.png)]
###服务端
工程名:hello-spring-cloud-zipkin
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>com.hang</groupId>
<artifactId>hello-spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>hello-spring-cloud-zipkin</artifactId>
<packaging>jar</packaging>
<!-- <name>hello-spring-cloud-zipkin</name>
<url>http://www.funtl.com</url>
<inceptionYear>2018-Now</inceptionYear>-->
<dependencies>
<!-- Spring Boot Begin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot End -->
<!-- Spring Cloud Begin -->
<!--服务链式追踪依赖-->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>
<!--服务注册与发现依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.hang.hello.spring.cloud.zipkin.ZipKinApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
启动类
@SpringBootApplication
@EnableEurekaClient
@EnableZipkinServer
public class ZipKinApplication {
public static void main(String[] args) {
SpringApplication.run(ZipKinApplication.class,args);
}
}
application.yml
spring:
application:
name: hello-spring-cloud-zipkin
server:
port: 9411
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8762/eureka/
management:
metrics:
web:
server:
auto-time-requests: false
port:默认端口
###客户端
这样服务端创建完成,再将需要监控的服务注册到zipkin服务中
在工程pom.xml加上依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
添加配置 application.yml
spring:
zipkin:
base-url: http://localhost:9411
1.8创建服务监控
随着开发周期的推移,项目会不断变大,切分出的服务也会越来越多,这时一个个的微服务构成了错综复杂的系统。对于各个微服务系统的健康状态、会话数量、并发数、服务资源、延迟等度量信息的收集就成为了一个挑战。Spring Boot Admin 应运而生,它正式基于这些需求开发出的一套功能强大的监控管理系统。
Spring Boot Admin 有两个角色组成,一个是 Spring Boot Admin Server,一个是 Spring Boot Admin Client,本章节将带领大家实现 Spring Boot Admin 的搭建。
服务端
工程名:hello-spring-cloud-admin
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>com.hang</groupId>
<artifactId>hello-spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>hello-spring-cloud-admin</artifactId>
<packaging>jar</packaging>
<name>hello-spring-cloud-admin</name>
<url>http://www.funtl.com</url>
<inceptionYear>2018-Now</inceptionYear>
<dependencies>
<!-- Spring Boot Begin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--服务监控依赖-->
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<!-- Spring Boot End -->
<!-- Spring Cloud Begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.hang.hello.spring.cloud.admin.AdminApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
application:
name: hello-spring-cloud-admin
zipkin:
base-url: http://localhost:9411
server:
port: 8084
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
# 注意:此处在视频里是 include: ["health", "info"] 但已无效了,请修改
include: health,info
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8762/eureka/
启动类
@SpringBootApplication
@EnableEurekaClient
@EnableAdminServer
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class,args);
}
}
客户端
pom.xml
<!--服务监控-->
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
application.yml
boot:
admin:
client:
url: http://localhost:8084
##2.创建服务提供者
(eurka客户端)
项目名:hello-spring-cloud-service-admin 此项目用于提供相应业务的服务
pom.xml :所需依赖和服务端一样
application.yml
spring:
application:
name: hello-spring-cloud-service-admin
server:
port: 8763
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8762/eureka/
@SpringBootApplication
@EnableEurekaClient
public class ServiceAdminApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceAdminApplication.class,args);
}
}
controller :提供一个请求
@RestController
public class UserController {
@Value("${server.port}")
private int port;
@RequestMapping("hi")
public String sayHi(String message){
return String.format("this is meagesss : %s ,this is port :%s",message,port);
}
}
##3.创建服务消费者
服务消费者, 熔断机制,和熔断监控((riabbon|feign)+hystrix+hystrix-dashboard)
在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于 http restful 的。Spring cloud 有两种服务调用方式,一种是 ribbon + restTemplate,另一种是 feign
###第一种: ribbon + restTemplate
项目名:hello-spring-cloud-web-admin-ribbon
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>com.hang</groupId>
<artifactId>hello-spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>hello-spring-cloud-web-admin-ribbon</artifactId>
<packaging>jar</packaging>
<!-- <name>hello-spring-cloud-web-admin-ribbon</name>
<url>http://www.funtl.com</url>
<inceptionYear>2018-Now</inceptionYear>-->
<dependencies>
<!-- Spring Boot Begin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot End -->
<!-- Spring Cloud Begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- Spring Cloud End -->
<!-- 解决 thymeleaf 模板引擎一定要执行严格的 html5 格式校验问题 -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<!--设置熔断器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--设置熔断器监控-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.hang.hello.spring.cloud.web.admin.ribbon.WebAdminRibbonApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
application:
name: hello-spring-cloud-web-admin-ribbon
thymeleaf:
cache: false
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
server:
port: 8765
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8762/eureka/
启动类:
@EnableDiscoveryClient
@SpringBootApplication
@EnableHystrix
@EnableHystrixDashboard
public class WebAdminRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminRibbonApplication.class,args);
}
}
config
@Configuration
public class RestTemplateConfiguration {
/*loadbalanced 可以使用负载均衡*/
@Bean
@LoadBalanced
public RestTemplate RestTemplate(){
return new RestTemplate();
}
/**
* 配置熔断器监控
* @return
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
service
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
//指定熔断方法
@HystrixCommand(fallbackMethod = "hiError")
public String sayHi(String message){
//指定服务器调用服务请求,如调用hello-spring-cloud-service-admin服务,在2.pom.xml
// spring:application:name指定
return restTemplate.getForObject("http://hello-spring-cloud-service-admin/hi? message="+message,String.class);
}
//这里是熔断方法, 当请求不成功,如网路原因、服务宕机等,调用
public String hiError(String message){
return String.format("this is error %s but request bad",message);
}
}
controller
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("hi")
public String sayHi(String message){
return userService.sayHi(message);
}
第二种feign
项目名:hello-spring-cloud-web-admin-feign
feign:默认集成hystrix熔断,只需开启配置即可
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>com.hang</groupId>
<artifactId>hello-spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>hello-spring-cloud-web-admin-feign</artifactId>
<packaging>jar</packaging>
<!-- <name>hello-spring-cloud-web-admin-ribbon</name>
<url>http://www.funtl.com</url>
<inceptionYear>2018-Now</inceptionYear>-->
<dependencies>
<!-- Spring Boot Begin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot End -->
<!-- Spring Cloud Begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Spring Cloud End -->
<!-- 解决 thymeleaf 模板引擎一定要执行严格的 html5 格式校验问题 -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<!--设置熔断器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--设置熔断器监控-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.hang.hello.spring.cloud.web.admin.feign.WebAdminFeignApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
application:
name: hello-spring-cloud-web-admin-feign
thymeleaf:
cache: false
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
feign:
hystrix:
enabled: true
server:
port: 8766
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrixDashboard
public class WebAdminFeignApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminFeignApplication.class,args);
}
}
service
//指定熔断类,指定服务地址
@FeignClient(value = "hello-spring-cloud-service-admin",fallback = UserServiceHystrix.class)
public interface UserService {
@RequestMapping("hi")
String syaHi(@RequestParam("message") String message);
}
hystrix
//熔断类
@Component
public class UserServiceHystrix implements UserService {
@Override
public String syaHi(String message) {
return "this is request bad "+message;
}
}
controller
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("hi")
public String sayHi(String message){
return userService.syaHi(message);
}
}
熔断监控
config
@Configuration
public class HystrixDashboardConfiguration {
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
##4.创建服务网关,
管理服务消费者,创建服务熔断,(zuul)
项目名:hello-spring-cloud-zuul
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>com.hang</groupId>
<artifactId>hello-spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>hello-spring-cloud-zuul</artifactId>
<packaging>jar</packaging>
<!--<name>hello-spring-cloud-zuul</name>
<url>http://www.funtl.com</url>
<inceptionYear>2018-Now</inceptionYear>
-->
<dependencies>
<!-- Spring Boot Begin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot End -->
<!-- Spring Cloud Begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 网关依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.hang.hello.spring.cloud.zuul.ZuulApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
application:
name: hello-spring-cloud-zuul
server:
port: 8769
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8762/eureka/
zuul:
routes:
api-a:
path: /api/a/**
serviceId: hello-spring-cloud-web-admin-ribbon
api-b:
path: /api/b/**
serviceId: hello-spring-cloud-web-admin-feign
api/a api/b,请求路径分别制定两个服务,这时管理两个服务
启动类
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
熔断
fallback
@Component
public class UserServiceRibbonFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
return "hello-spring-cloud-web-admin-ribbon";
}
/* @Override
public String getRoute() {
// ServiceId,如果需要所有调用都支持回退,则 return "*" 或 return null
return "hello-spring-cloud-web-admin-feign";
}*/
/**
* 如果请求服务失败,则返回指定的信息给调用者
* @param route
* @param cause
* @return
*/
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
/**
* 网关向 api 服务请求失败了,但是消费者客户端向网关发起的请求是成功的,
* 不应该把 api 的 404,500 等问题抛给客户端
* 网关和 api 服务集群对于客户端来说是黑盒
* @return
* @throws IOException
*/
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.OK.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.OK.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("message", "无法连接,请检查您的网络");
return new ByteArrayInputStream(objectMapper.writeValueAsString(map).getBytes("UTF-8"));
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
// 和 getBody 中的内容编码一致
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
return headers;
}
};
}
}
过滤器
filter
/**
* 登陆拦截器
*/
@Component
public class LoginFilter extends ZuulFilter {
private static final Logger logger = LoggerFactory.getLogger(LoginFilter.class);
/**
* 配置过滤类型,有四种不同生命周期的过滤器类型
* 1. pre:路由之前
* 2. routing:路由之时
* 3. post:路由之后
* 4. error:发送错误调用
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 配置过滤的顺序
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 配置是否需要过滤:true/需要,false/不需要
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器的具体业务代码
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
logger.info("{} >>> {}", request.getMethod(), request.getRequestURL().toString());
String token = request.getParameter("token");
if (token == null) {
logger.warn("Token is empty");
context.setSendZuulResponse(false);
context.setResponseStatusCode(401);
try {
context.getResponse().getWriter().write("Token is empty");
} catch (IOException e) {
}
} else {
logger.info("OK");
}
return null;
}
}
5.项目配置管理
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在 Spring Cloud 中,有分布式配置中心组件 Spring Cloud Config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程 Git 仓库中。在 Spring Cloud Config 组件中,分两个角色,一是 Config Server,二是 Config Client。
1.服务端
工程名:hello-spring-cloud-config
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>com.hang</groupId>
<artifactId>hello-spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>hello-spring-cloud-config</artifactId>
<packaging>jar</packaging>
<!-- <name>hello-spring-cloud-config</name>
<url>http://www.funtl.com</url>
<inceptionYear>2018-Now</inceptionYear>-->
<dependencies>
<!-- Spring Boot Begin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot End -->
<!-- Spring Cloud Begin -->
<!--配置管理服务依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.hang.hello.spring.cloud.config.ConfigApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
application:
name: hello-spring-cloud-config
cloud:
config:
label: master
server:
git:
uri: http://192.168.221.133:8080/xuang/hello-spring-cloud.git
search-paths: respo
username: xuang
password: 12345678
server:
port: 8888
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8762/eureka/
spring.cloud.config.label
:配置仓库的分支spring.cloud.config.server.git.uri
:配置 Git 仓库地址(GitHub、GitLab、码云 …)spring.cloud.config.server.git.search-paths
:配置仓库路径(存放配置文件的目录)spring.cloud.config.server.git.username
:访问 Git 仓库的账号spring.cloud.config.server.git.password
:访问 Git 仓库的密码
启动类
@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class,args);
}
}
gitlab服务器资源结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MXtNkTgr-1610092415210)(C:\Users\DELL\Pictures\截屏\捕获.PNG)]
respo:下存放所有application。yml文件
如feign消费者服务配置文件改为web-admin-feign-dev.yml,web-admin-feign-prod.yml上传gitlab
测试一下:http://ip:8080/文件名/分支:http://localhost:8888/web-admin-feign-dev/master
查看到配置文件信息即可
###2.客户端
在工程:hello-spring-cloud-web-admin-feign修改application.yml文件
spring:
cloud:
config:
uri: http://localhost:8888
name: web-admin-feign
label: master
profile: dev
spring.cloud.config.uri
:配置服务中心的网址spring.cloud.config.name
:配置文件名称的前缀spring.cloud.config.label
:配置仓库的分支spring.cloud.config.profile
:配置文件的环境标识- dev:表示开发环境
- test:表示测试环境
- prod:表示生产环境
- 配置服务器的默认端口为
8888
,如果修改了默认端口,则客户端项目就不能在application.yml
或application.properties
中配置spring.cloud.config.uri
,必须在bootstrap.yml
或是bootstrap.properties
中配置,原因是bootstrap
开头的配置文件会被优先加载和配置,切记。
再添加一个application-pro.xml文件 ,此时指定的配置文件为生产环境的配置文件
spring:
cloud:
config:
uri: http://localhost:8888
name: web-admin-feign
label: master
profile: prod
操作起来很简单,只需要为不同的环境编写专门的配置文件,如:application-dev.yml
、application-prod.yml
, 启动项目时只需要增加一个命令参数 --spring.profiles.active=环境配置
即可,启动命令如下: 测试一下在项目存放路径,使用cmd运行jar包
java -jar hello-spring-cloud-web-admin-feign-1.0.0-SNAPSHOT.jar --spring.profiles.active=prod
word`:访问 Git 仓库的密码
启动类
@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class,args);
}
}
gitlab服务器资源结构
[外链图片转存中…(img-MXtNkTgr-1610092415210)]
respo:下存放所有application。yml文件
如feign消费者服务配置文件改为web-admin-feign-dev.yml,web-admin-feign-prod.yml上传gitlab
测试一下:http://ip:8080/文件名/分支:http://localhost:8888/web-admin-feign-dev/master
查看到配置文件信息即可
###2.客户端
在工程:hello-spring-cloud-web-admin-feign修改application.yml文件
spring:
cloud:
config:
uri: http://localhost:8888
name: web-admin-feign
label: master
profile: dev
spring.cloud.config.uri
:配置服务中心的网址spring.cloud.config.name
:配置文件名称的前缀spring.cloud.config.label
:配置仓库的分支spring.cloud.config.profile
:配置文件的环境标识- dev:表示开发环境
- test:表示测试环境
- prod:表示生产环境
- 配置服务器的默认端口为
8888
,如果修改了默认端口,则客户端项目就不能在application.yml
或application.properties
中配置spring.cloud.config.uri
,必须在bootstrap.yml
或是bootstrap.properties
中配置,原因是bootstrap
开头的配置文件会被优先加载和配置,切记。
再添加一个application-pro.xml文件 ,此时指定的配置文件为生产环境的配置文件
spring:
cloud:
config:
uri: http://localhost:8888
name: web-admin-feign
label: master
profile: prod
操作起来很简单,只需要为不同的环境编写专门的配置文件,如:application-dev.yml
、application-prod.yml
, 启动项目时只需要增加一个命令参数 --spring.profiles.active=环境配置
即可,启动命令如下: 测试一下在项目存放路径,使用cmd运行jar包
java -jar hello-spring-cloud-web-admin-feign-1.0.0-SNAPSHOT.jar --spring.profiles.active=prod