Spring cloud
微服务技术栈
微服务条目 | 落地技术 | 备注 |
---|---|---|
服务开发 | Spring Boot、Spring、Spring MVC | |
服务配置与管理 | Netfix公司的Archaius、阿里的Diamond等 | |
服务注册与发现 | Eureka、Consule、Zookeeper | |
服务调用 | Rest、RPC | |
服务熔断 | Hystrix等 | |
负载均衡 | Ribbon、Nignx等 | |
服务接口调用 | Feign等 | |
服务配置中心管理 | SpringCloud Config、Chef等 | |
服务路由(网关) | Zuul等 | |
服务监控 | Zabbix、Spectaor等 | |
全链路追踪 | Zipkin,Brave、Dapper等 | |
服务部署 | Docker、OpenStack等 | |
数据流操作开发部 | SpringCloud Stream | |
事件消息总线 | Spring Cloud Bus | |
… |
Spring cloud部署
统一的依赖管理dependencies
创建springcloud-dependencies项目,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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<groupId>com.shyb</groupId>
<artifactId>springcloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<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>Greenwich.SR1</spring-cloud.version>
<zipkin.version>2.10.1</zipkin.version>
<spring.boot.admin.version>2.1.5</spring.boot.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>
<!-- zipkin链路追踪 begin-->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
<version>${zipkin.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</exclusion>
</exclusions>
<version>${zipkin.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>${zipkin.version}</version>
</dependency>
<!-- zipkin链路追踪 end-->
<!-- admin服务监控 begin-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring.boot.admin.version}</version>
</dependency>
<!-- admin服务监控 begin-->
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 所有子工程都需要的依赖 start -->
<!-- eureka start-->
<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.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- eureka end-->
</dependencies>
<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>
服务注册与发现Eureka
1. 创建springcloud-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.shyb</groupId>
<artifactId>springcloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../springcloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>springcloud-eureka</artifactId>
<packaging>jar</packaging>
<dependencies>
<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.shyb.springcloud.eureka.EurekaApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 启动类开启eureka server注解
package com.shyb.springcloud.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author wzh
* @date 2019/6/4 - 10:12
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class,args);
}
}
3. application.yml配置
spring:
cloud:
config:
uri: localhost:8888
name: eureka
label: master
profile: dev
服务提供者(注册)
config配置中心
1. springcloud-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.shyb</groupId>
<artifactId>springcloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../springcloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>springcloud-config</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- Spring Cloud Begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.shyb.springcloud.config.ConfigApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 启动类注册到eureka,开启config server
package com.shyb.springcloud.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author wzh
* @date 2019/6/17 - 21:27
*/
@EnableConfigServer
@EnableEurekaClient
@SpringBootApplication
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class,args);
}
}
3. application.yml配置
注意事项: config配置中心的server.port在application.yml只能配8888,要换需要在bootstrap.yml配置(优先级高于application.yml)
spring:
application:
name: springcloud-config
cloud:
config:
label: master
server:
git:
uri: https://github.com/www5978058/springcloud-config.git
search-paths: respo
username: www5978058
password: ********
server:
port: 8888
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
zipkin链路追踪
springcloud-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.shyb</groupId>
<artifactId>springcloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../springcloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>springcloud-zipkin</artifactId>
<packaging>jar</packaging>
<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-config</artifactId>
</dependency>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.shyb.springcloud.zipkin.ZipKinApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
yml配置
spring:
cloud:
config:
uri: localhost:8888
name: zipkin
label: master
profile: dev
启动类配置
package com.shyb.springcloud.zipkin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import zipkin.server.internal.EnableZipkinServer;
/**
* @author wzh
* @date 2019/6/18 - 9:35
*/
@EnableZipkinServer
@EnableEurekaClient
@SpringBootApplication
public class ZipKinApplication {
public static void main(String[] args) {
SpringApplication.run(ZipKinApplication.class,args);
}
}
admin服务监控
springcloud-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.shyb</groupId>
<artifactId>springcloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../springcloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>springcloud-admin</artifactId>
<packaging>jar</packaging>
<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-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-config</artifactId>
</dependency>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.shyb.springcloud.admin.AdminApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
yml配置
spring:
cloud:
config:
uri: localhost:8888
name: admin
label: master
profile: dev
启动类注册进eureka,开启admin Server
package com.shyb.springcloud.admin;
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author wzh
* @date 2019/6/18 - 11:13
*/
@EnableAdminServer
@EnableEurekaClient
@SpringBootApplication
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class,args);
}
}
业务提供
1. springcloud-service-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.shyb</groupId>
<artifactId>springcloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../springcloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>springcloud-service-admin</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.shyb.springcloud.service.admin.ServiceAdminApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 启动类配置服务 client
package com.shyb.springcloud.service.admin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author wzh
* @date 2019/6/4 - 10:32
*/
@EnableEurekaClient
@SpringBootApplication
public class ServiceAdminApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceAdminApplication.class,args);
}
}
3. application.yml配置
spring:
application:
name: springcloud-service-admin
zipkin:
base-url: http://localhost:9411
server:
port: 8763
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
4. 配置业务逻辑,提供API接口
package com.shyb.springcloud.service.admin.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wzh
* @date 2019/6/4 - 10:38
*/
@RestController
public class AdminController {
@Value("${server.port}")
private String port;
@GetMapping("/")
public String hello(){
return "你的端口是"+port;
}
@GetMapping("/show")
public String show(String message){
return "你的消息是"+",端口是"+port;
}
}
服务消费者(发现)
ribbon+hystrix
springcloud-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.shyb</groupId>
<artifactId>springcloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../springcloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>springcloud-web-admin-ribbon</artifactId>
<packaging>jar</packaging>
<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-ribbon</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-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<!-- Spring Cloud End -->
<!-- 解决 thymeleaf 模板引擎一定要执行严格的 html5 格式校验问题 -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.shyb.springcloud.web.admin.ribbon.WebAdminRibbonApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
启动类配置 增加服务发现和开启断路器
package com.shyb.springcloud.web.admin.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
/**
* @author wzh
* @date 2019/6/4 - 10:49
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
public class WebAdminRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminRibbonApplication.class,args);
}
}
yml配置
spring:
cloud:
config:
uri: localhost:8888
name: web-admin-ribbon
label: master
profile: dev
配置restTemplate
package com.shyb.springcloud.web.admin.ribbon.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author wzh
* @date 2019/6/4 - 10:58
*/
@Configuration
public class RestTemplateConfiguration {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
rest调用和断路调用
package com.shyb.springcloud.web.admin.ribbon.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* @author wzh
* @date 2019/6/16 - 14:59
*/
@Service
public class AdminService {
private static final String ADMIN_SERVER_URL = "http://SPRINGCLOUD-SERVICE-ADMIN/";
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiError")
public String hello(){
return restTemplate.getForObject(ADMIN_SERVER_URL,String.class);
}
@HystrixCommand(fallbackMethod = "showError")
public String show(String message){
return restTemplate.getForObject(ADMIN_SERVER_URL+"show?message="+message,String.class);
}
public String hiError(){
return "your request bad";
}
public String showError(String message){
return String.format("your message is %s, but your request bad",message);
}
}
对外暴露接口
package com.shyb.springcloud.web.admin.ribbon.controller;
import com.shyb.springcloud.web.admin.ribbon.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wzh
* @date 2019/6/16 - 15:03
*/
@RestController
public class AdminController {
@Autowired
private AdminService adminService;
@GetMapping("/")
public String hello(){
return adminService.hello();
}
@GetMapping("/show")
public String show(String message){
return adminService.show(message);
}
}
feign(封装了ribbon 常用)+hystrix
建立springcloud-web-admin-feign项目,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.shyb</groupId>
<artifactId>springcloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../springcloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>springcloud-web-admin-feign</artifactId>
<packaging>jar</packaging>
<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-openfeign</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-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!-- Spring Cloud End -->
<!-- 解决 thymeleaf 模板引擎一定要执行严格的 html5 格式校验问题 -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.shyb.springcloud.web.admin.feign.WebAdminFeignApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml配置(需要feign.hystrix.enabled=true开启断路)
spring:
cloud:
config:
uri: localhost:8888
name: web-admin-feign
label: master
profile: prod
启动类开启服务发现、断路器和Feign注解
package com.shyb.springcloud.web.admin.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
/**
* @author wzh
* @date 2019/6/4 - 10:49
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrixDashboard
public class WebAdminRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminRibbonApplication.class,args);
}
}
建立业务接口,使用FeignClient注解,value指定spring.application.name,fallback指定
返回实现类,实现类的方法就是断路后的方法
package com.shyb.springcloud.web.admin.feign.service;
import com.shyb.springcloud.web.admin.feign.service.hystrix.AdminServiceHystrix;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author wzh
* @date 2019/6/16 - 15:16
*/
@FeignClient(value = "SPRINGCLOUD-SERVICE-ADMIN",fallback = AdminServiceHystrix.class)
public interface AdminService {
@GetMapping("/")
public String sayHi();
/**
* 需要使用@RequestParam注解,该注解作为参数传递
* @param message
* @return
*/
@GetMapping("/show")
public String show(@RequestParam("message") String message);
}
package com.shyb.springcloud.web.admin.feign.service.hystrix;
import com.shyb.springcloud.web.admin.feign.service.AdminService;
import org.springframework.stereotype.Component;
/**
* @author wzh
* @date 2019/6/16 - 15:35
*/
@Component
public class AdminServiceHystrix implements AdminService {
@Override
public String sayHi() {
return "your request is bad";
}
@Override
public String show(String message) {
return String.format("your message is %s,but it is bad",message);
}
}
对外提供访问
package com.shyb.springcloud.web.admin.feign.controller;
import com.shyb.springcloud.web.admin.feign.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wzh
* @date 2019/6/16 - 15:17
*/
@RestController
public class AdminController {
@Autowired
AdminService adminService;
@GetMapping("/")
public String sayHi(){
return adminService.sayHi();
}
@GetMapping("/show")
public String show(String message){
return adminService.show(message);
}
}
配置断路监控HystrixMetricsStreamServlet
package com.shyb.springcloud.web.admin.feign.config;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author wzh
* @date 2019/6/16 - 15:40
*/
@Configuration
public class HystrixDashboardConfiguration {
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
路由网关(zuul)
springcloud-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.shyb</groupId>
<artifactId>springcloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../springcloud-dependencies/pom.xml</relativePath>
</parent>
<artifactId>springcloud-zuul</artifactId>
<packaging>jar</packaging>
<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-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- Spring Cloud End -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.shyb.springcloud.zuul.ZuulApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
yml配置(zuul.routs配置map)
spring:
cloud:
config:
uri: localhost:8080
name: zuul
label: master
profile: dev
启动类配置,注册到eureka,开启zuul代理
package com.shyb.springcloud.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
/**
* @author wzh
* @date 2019/6/16 - 16:00
*/
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
网关失败回调
package com.shyb.springcloud.zuul.provide;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/**
* @author wzh
* @date 2019/6/16 - 16:22
*/
@Component
public class WebAdminFeignFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
return "SPRINGCLOUD-WEB-ADMIN-FEIGN";
}
@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;
}
};
}
}
网关过滤器
package com.shyb.springcloud.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author wzh
* @date 2019/6/17 - 15:31
*/
@Component
@Slf4j
public class LoginFilter extends ZuulFilter {
/**
* 配置过滤类型,有四种不同生命周期的过滤器类型
* 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();
log.info("{} >>> {}", request.getMethod(), request.getRequestURL().toString());
String token = request.getParameter("token");
if (token == null) {
log.warn("Token is empty");
context.setSendZuulResponse(false);
context.setResponseStatusCode(401);
try {
HttpServletResponse httpServletResponse = context.getResponse();
httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
httpServletResponse.getWriter().write("Token is empty啊啊啊");
} catch (IOException e) {
}
} else {
log.info("OK");
}
return null;
}
}
启动顺序
先启动eureka,再启动config配置中心和zipKin链路追踪,再启动admin服务监控和业务
提供,再启动业务消费,最后开启zuul网关。