此文章有參考李老師的博客鏈接,鳴謝!
SpringCloud
創建統一的依賴管理(spring-cloud-dependencies)
<?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.3.RELEASE</version>
</parent>
<groupId>com.qian</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>spring-cloud-dependencies</name>
<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>
<zipkin.version>2.10.1</zipkin.version>
<spring-boot-admin-starter-server.version>2.0.0</spring-boot-admin-starter-server.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>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
<version>${zipkin.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<version>${zipkin.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>${zipkin.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring-boot-admin-starter-server.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring-boot-admin-starter-server.version}</version>
</dependency>
</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>
<!--spring的maven倉庫-->
<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>
服務註冊與發現(spring-cloud-eureka)
<?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.qian</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-eureka</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-eureka</name>
<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>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.qian.spring.cloud.eureka.EurekaApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring:
application:
name: spring-cloud-eureka
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
Eureka 是一個高可用的組件,它沒有後端緩存,每一個實例註冊之後需要向註冊中心發送心跳(因此可以在內存中完成),在默認情況下 Erureka Server 也是一個 Eureka Client ,必須要指定一個 Server
通過 eureka.client.registerWithEureka:false
和 fetchRegistry:false
來表明自己是一個 Eureka Server
package com.qian.spring.cloud.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
服務提供者(spring-cloud-service-admin)
<?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.qian</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-service-admin</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-service-admin</name>
<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>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.qian.spring.cloud.service.admin.ServiceAdminApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring:
application:
name: spring-cloud-service-admin
server:
port: 8765
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
package com.qian.spring.cloud.service.admin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ServiceAdminApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceAdminApplication.class, args);
}
}
package com.qian.spring.cloud.service.admin.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AdminController {
@Value("${server.port}")
private String port;
@RequestMapping(value = "hi", method = RequestMethod.GET)
public String sayHi(@RequestParam(value = "message") String message) {
return String.format("Hi,your message is : %s i am from port : %s", message, port);
}
}
服務消費者(spring-cloud-web-admin-ribbon)
在微服務架構中,業務都會被拆分成一個獨立的服務,服務與服務的通訊是基於 http restful 的。Spring cloud 有兩種服務調用方式,一種是 ribbon + restTemplate,另一種是 feign。在這一篇文章首先講解下基於 ribbon + rest,Ribbon 是一個負載均衡客戶端,可以很好的控制 http
和 tcp
的一些行爲
<?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.qian</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-web-admin-ribbon</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-web-admin-ribbon</name>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.qian.spring.cloud.web.admin.ribbon.WebAdminRibbonApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring:
application:
name: spring-cloud-web-admin-ribbon
thymeleaf:
cache: false
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
server:
port: 8764
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
package com.qian.spring.cloud.web.admin.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
//註冊到服務中心
@EnableDiscoveryClient
public class WebAdminRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminRibbonApplication.class, args);
}
}
配置注入 RestTemplate
的 Bean,並通過 @LoadBalanced
註解表明開啓負載均衡功能
package com.qian.spring.cloud.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;
@Configuration
public class RestTemplateConfiguration {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
package com.qian.spring.cloud.web.admin.ribbon.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class AdminService {
@Autowired
private RestTemplate restTemplate;
public String sayHi(String message) {
return restTemplate.getForObject("http://SPRING-CLOUD-SERVICE-ADMIN/hi?message=" + message, String.class);
}
}
package com.qian.spring.cloud.web.admin.ribbon.controller;
import com.qian.spring.cloud.web.admin.ribbon.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AdminController {
@Autowired
private AdminService adminService;
@RequestMapping(value = "hi", method = RequestMethod.GET)
public String sayHi(@RequestParam String message) {
return adminService.sayHi(message);
}
}
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6qcKnbaV-1587296410234)(C:\Users\swing\Desktop\筆記\知識點截圖\Lusifer201805292246004.png)]
服務消費者 (spring-cloud-web-admin-feign) (常用這個)
Feign 是一個聲明式的僞 Http 客戶端,它使得寫 Http 客戶端變得更簡單。使用 Feign,只需要創建一個接口並註解。它具有可插拔的註解特性,可使用 Feign 註解和 JAX-RS 註解。Feign 支持可插拔的編碼器和解碼器。Feign 默認集成了 Ribbon,並和 Eureka 結合,默認實現了負載均衡的效果
- Feign 採用的是基於接口的註解
- Feign 整合了 ribbon
<?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.qian</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-web-admin-feign</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-web-admin-feign</name>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.qian.spring.cloud.web.admin.feign.WebAdminFeignApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring:
application:
name: spring-cloud-web-admin-feign
thymeleaf:
cache: false
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
server:
port: 8763
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
package com.qian.spring.cloud.web.admin.feign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class WebAdminFeignApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminFeignApplication.class, args);
}
}
通過 @FeignClient("服務名")
註解來指定調用哪個服務(服務名在對應服務的yml配置文件內)
package com.qian.spring.cloud.web.admin.feign.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "spring-cloud-service-admin")
public interface AdminService {
@RequestMapping(value = "hi", method = RequestMethod.GET)
public String sayHi(@RequestParam(value = "message") String message);
}
package com.qian.spring.cloud.web.admin.feign.controller;
import com.qian.spring.cloud.web.admin.feign.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AdminController {
@Autowired
private AdminService adminService;
@RequestMapping(value = "hi", method = RequestMethod.GET)
public String sayHi(@RequestParam String message) {
return adminService.sayHi(message);
}
}
Feign中使用熔斷器防止雪崩
Feign 是自帶熔斷器的,但默認是關閉的。需要在配置文件中配置打開它,在application.yml文件增加以下代碼:
feign:
hystrix:
enabled: true
package com.qian.spring.cloud.web.admin.feign.service.hystrix;
import com.qian.spring.cloud.web.admin.feign.service.AdminService;
import org.springframework.stereotype.Component;
@Component
public class AdminServiceHystrix implements AdminService {
@Override
public String sayHi(String message) {
return "Hi,your message is :\"" + message + "\" but request error.";
}
}
package com.qian.spring.cloud.web.admin.feign.service;
import com.qian.spring.cloud.web.admin.feign.service.hystrix.AdminServiceHystrix;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
//聲明服務名
@FeignClient(value = "spring-cloud-service-admin", fallback = AdminServiceHystrix.class)
public interface AdminService {
@RequestMapping(value = "hi", method = RequestMethod.GET)
public String sayHi(@RequestParam(value = "message") String message);
}
-
使用熔斷器儀表盤監控
- 在 feign 中 pom.xml 增加依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>
- 在 WebAdminRibbonApplication.java 中添加
@EnableHystrixDashboard
- 增加一個配置類
package com.qian.spring.cloud.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; @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; } }
使用路由網關同意訪問接口(spring-cloud-zuul)
<?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.qian</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-zuul</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-zuul</name>
<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 -->
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.qian.spring.cloud.zuul.ZuulApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring:
application:
name: spring-cloud-zuul
zipkin:
base-url: http://localhost:9411
boot:
admin:
client:
url: http://localhost:8084
server:
port: 8581
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8501/eureka/
zuul:
routes:
api-a:
path: /api/a/**
serviceId: spring-cloud-web-admin-ribbon
api-b:
path: /api/b/**
serviceId: spring-cloud-web-admin-feign
package com.qian.spring.cloud.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;
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
package com.qian.spring.cloud.zuul.fallback;
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;
/**
* 路由 hello-spring-cloud-web-admin-feign 失敗時的回調
* <p>Title: WebAdminFeignFallbackProvider</p>
* <p>Description: </p>
*
* @author Lusifer
* @version 1.0.0
* @date 2018/7/27 6:55
*/
@Component
public class WebAdminFeignFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
// ServiceId,如果需要所有調用都支持回退,則 return "*" 或 return null
return "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;
}
};
}
}
package com.qian.spring.cloud.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Zuul 的服務過濾演示
* <p>Title: LoginFilter</p>
* <p>Description: </p>
*
* @author Lusifer
* @version 1.0.0
* @date 2018/5/29 22:02
*/
@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 {
HttpServletResponse response = context.getResponse();
response.setContentType("text/html:charset=utf-8");
context.getResponse().getWriter().write("Token is empty");
} catch (IOException e) {
}
} else {
logger.info("OK");
}
return null;
}
}
將配置文件託管到 Git 上 (spring-cloud-config)
<?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.qian</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-config</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-config</name>
<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 -->
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.qian.spring.cloud.config.ConfigApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.qian.spring.cloud.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;
@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
}
spring:
application:
name: spring-cloud-config
zipkin:
base-url: http://localhost:9411
boot:
admin:
client:
url: http://localhost:8084
cloud:
config:
label: master
server:
git:
uri: https://github.com/qiu-qian/spring-config.git
search-paths: config
username: qiu-qian
password: LQqhzn18845124018
server:
port: 8888
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8501/eureka/
- 之後在 https://github.com/qiu-qian/spring-config.git/config 中增加所需的配置文件 web-admin-feign-dev (prod)
假設將 spring-cloud-web-admin-feign 的配置文件放入git 上保管
修改對應的application.yml
spring:
cloud:
config:
uri: http://localhost:8888
name: web-admin-feign
label: master
profile: dev
增加 依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
我們在做項目開發的時候,生產環境和測試環境的一些配置可能會不一樣,有時候一些功能也可能會不一樣,所以我們可能會在上線的時候手工修改這些配置信息。但是 Spring 中爲我們提供了 Profile 這個功能。我們只需要在啓動的時候添加一個虛擬機參數,激活自己環境所要用的 Profile 就可以了。
操作起來很簡單,只需要爲不同的環境編寫專門的配置文件,如:application-dev.yml
、application-prod.yml
, 啓動項目時只需要增加一個命令參數 --spring.profiles.active=環境配置
即可,啓動命令如下:
java -jar spring-cloud-web-admin-feign-1.0.0-SNAPSHOT.jar --spring.profiles.active=prod
ZipKin 服務鏈路追蹤 (spring-cloud-zipkin)
<?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.qian</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-zipkin</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-zipkin</name>
<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 -->
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.qian.spring.cloud.zipkin.ZipKinApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
- application.yml
spring:
application:
name: spring-cloud-zipkin
boot:
admin:
client:
url: http://localhost:8084
server:
port: 9411
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8501/eureka/
management:
metrics:
web:
server:
auto-time-requests: false
在 所有需要被追蹤的項目(就當前教程而言,除了 dependencies
項目外都需要被追蹤,包括 Eureka Server)中增加 spring-cloud-starter-zipkin
依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
在這些項目的 application.yml
配置文件中增加 Zipkin Server 的地址即可
spring:
zipkin:
base-url: http://localhost:9411
Sprign Boot Admin 總控制界面 (spring-cloud-admin)
<?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.qian</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-admin</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-admin</name>
<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.qian.spring.cloud.admin.AdminApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring:
application:
name: 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:8501/eureka/
- AdminApplication.java
package com.qian.spring.cloud.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;
@SpringBootApplication
@EnableEurekaClient
@EnableAdminServer
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}
}
-
在其他的模塊中如下修改 (spring-cloud-admin 和 dependencies 除外)
- 增加依賴
<dependency> <groupId>org.jolokia</groupId> <artifactId>jolokia-core</artifactId> </dependency> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-client</artifactId> </dependency>
- 增加配置
spring: boot: admin: client: url: http://localhost:8084
服務啓動順序
- eureka
- config
- zipkin
- admin
- service-admin
- web-admin-feign
- zuul