springcloud
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的開發便利性巧妙地簡化了分佈式系統基礎設施的開發,如服務發現註冊、配置中心、消息總線、負載均衡、斷路器、數據監控等,都可以用Spring Boot的開發風格做到一鍵啓動和部署。Spring Cloud並沒有重複製造輪子,它只是將目前各家公司開發的比較成熟、經得起實際考驗的服務框架組合起來,通過Spring Boot風格進行再封裝屏蔽掉了複雜的配置和實現原理,最終給開發者留出了一套簡單易懂、易部署和易維護的分佈式系統開發工具包。現在我們一一體驗一下這些組件的功能作用。首先從服務提供者和消費者開始。
Rest項目演練
microcloud-api 模塊,作爲公共的信息導入配置模塊;
microcloud-provider-product:作爲服務提供者;
microcloud-consumer:作爲微服務調用的客戶端使用;
新建一個maven父項目:microcloud
其中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>
<groupId>hdk</groupId>
<artifactId>springcloud</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>microcloudapi</module>
<module>microcloudproviderproduct</module>
<module>microcloudconsumer</module>
</modules>
<properties>
<jdk.version>1.8</jdk.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency> <!-- 進行SpringCloud依賴包的導入處理 -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency> <!-- SpringCloud離不開SpringBoot,所以必須要配置此依賴包 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>microcloud</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${jdk.version}</source><!-- 源代碼使用的開發版本 -->
<target>${jdk.version}</target><!-- 需要生成的目標class文件的編譯版本 -->
</configuration>
</plugin>
</plugins>
</build>
</project>
microcloud-api
【microcloud-api】模塊,建立一個公共模板,這模塊的主要功能是提供公共處理的工具類,實體,接口等。
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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-api</artifactId>
<version>1.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
由於實體對象不管是服務提供放還是消費者都需要用到,實體對象先創建到api模塊中,創建一個Product實體
package hdk.vo;
import java.io.Serializable;
public class Product implements Serializable {
private Long productId;
private String productName;
private String productDesc;
public String getProductDesc() {
return productDesc;
}
public void setProductDesc(String productDesc) {
this.productDesc = productDesc;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
@Override
public String toString() {
return "Product{" +
"productId=" + productId +
", productName='" + productName + '\'' +
", productDesc='" + productDesc + '\'' +
'}';
}
}
由於實體對象不管是服務提供放還是消費者都需要用到,實體對象先創建到api模塊中,創建一個Product實體
package cn.hdk.vo;
import java.io.Serializable;
public class Product implements Serializable {
private Long productId;
private String productName;
private String productDesc;
public String getProductDesc() {
return productDesc;
}
public void setProductDesc(String productDesc) {
this.productDesc = productDesc;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
@Override
public String toString() {
return "Product{" +
"productId=" + productId +
", productName='" + productName + '\'' +
", productDesc='" + productDesc + '\'' +
'}';
}
}
服務提供方
創建一個Product Rest提供者的項目模塊,這個模塊對應的數據庫腳本如下
CREATE DATABASE springcloud CHARACTER SET UTF8 ;
USE springcloud ;
CREATE TABLE product (
prodcutId BIGINT AUTO_INCREMENT ,
productName VARCHAR(50) ,
productDesc VARCHAR(50) ,
CONSTRAINT pk_prodcut_id PRIMARY KEY(prodcutId)
) ;
INSERT INTO product(productName,productDesc) VALUES ('電子鎖骨',database()) ;
INSERT INTO product(productName,productDesc) VALUES ('Springboot',database()) ;
INSERT INTO product(productName,productDesc) VALUES ('水錶',database()) ;
INSERT INTO product(productName,productDesc) VALUES ('門禁',database()) ;
INSERT INTO product(productName,productDesc) VALUES ('攝像頭',database()) ;
【microcloud-provider-product】模塊繼續使用mybaits對數據庫進行操作,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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>1.0.0</version>
<artifactId>microcloud-provider-product</artifactId>
<dependencies>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-provider-product】創建一個ProductMapper對數據庫的操作接口,這個接口方法特別簡單
package hdk.mapper;
import hdk.vo.Product;
import java.util.List;
public interface ProductMapper {
boolean create(Product product);
public Product findById(Long id);
public List<Product> findAll();
}
【microcloud-provider-product】新增修改application.yml文件,追加對mybatis以及數據庫的支持
server:
port: 8080
mybatis:
mapper-locations: # 所有的mapper映射文件
- classpath:mapping/*.xml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 配置當前要使用的數據源的操作類型
driver-class-name: com.mysql.cj.jdbc.Driver # 配置MySQL的驅動程序類
url: jdbc:mysql://localhost:3306/springcloud?serverTimezone=GMT%2B8 # 數據庫連接地址
username: root # 數據庫用戶名
password: 111111% # 數據庫連接密碼
logging:
level:
hdk.mapper: debug
【microcloud-provider-product】創建修改src/main/resources/mapping/ProductMapper.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="hdk.mapper.ProductMapper">
<select id="findById" resultType="cn.hdk.vo.Product" parameterType="long">
select productId,productName,productDesc from product WHERE productId=#{id} ;
</select>
<select id="findAll" resultType="cn.hdk.vo.Product">
SELECT productId,productName,productDesc from product;
</select>
<insert id="create" parameterType="cn.hdk.vo.Product">
INSERT INTO product(productName,productDesc) VALUES (#{productName},database()) ;
</insert>
</mapper>
【microcloud-provider-product】建立IProductService接口,並創建相關實現類
package hdk.service;
import hdk.vo.Product;
import java.util.List;
public interface IProductService {
Product get(long id);
boolean add(Product product);
List<Product> list();
}
package hdk.service.impl;
import hdk.mapper.ProductMapper;
import hdk.service.IProductService;
import hdk.vo.Product;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class ProductServiceImpl implements IProductService {
@Resource
private ProductMapper productMapper;
@Override
public Product get(long id) {
return productMapper.findById(id);
}
@Override
public boolean add(Product product) {
return productMapper.create(product);
}
@Override
public List<Product> list() {
return productMapper.findAll();
}
}
【microcloud-provider-product】 定義主程序類,並定義好mapper掃描包
package hdk;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("hdk.mapper")
public class ProductApp{
public static void main(String[] args) {
SpringApplication.run(ProductApp.class,args);
}
}
【microcloud-provider-product】編寫單元測試
package hdk;
import hdk.service.IProductService;
import hdk.vo.Product;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@SpringBootTest(classes = ProductApp.class)
@RunWith(SpringRunner.class)
public class ProductServiceTest {
@Resource
private IProductService iProductService;
@Test
public void testGet() {
System.out.println(iProductService.get(1));
}
@Test
public void testAdd() {
Product dept = new Product() ;
dept.setProductName("lison-" + System.currentTimeMillis());
System.out.println(iProductService.add(dept));
}
@Test
public void testList() {
System.out.println(iProductService.list());
}
}
【microcloud-provider-product】建立ProductController建立一個Rest服務類
package hdk.controller;
import hdk.service.IProductService;
import hdk.vo.Product;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("/prodcut")
public class ProductController {
@Resource
private IProductService iProductService;
@RequestMapping(value="/get/{id}")
public Object get(@PathVariable("id") long id) {
return this.iProductService.get(id) ;
}
@RequestMapping(value="/add")
public Object add(@RequestBody Product product) {
return this.iProductService.add(product) ;
}
@RequestMapping(value="/list")
public Object list() {
return this.iProductService.list() ;
}
}
瀏覽器訪問:
調用get請求:localhost:8080/product/get/1
調用list請求:localhost:8080/product/list
服務消費方
創建一個maven新模塊:【microcloud-consumer】這個模塊作爲服務的消費方,調用前面的product服務
【microcloud-consumer】修改pom文件,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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-consumer</artifactId>
<dependencies>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-consumer】修改application.yml配置文件
server:
port: 80
【microcloud-consumer】創建Rest配置類,在這需要調用Rest服務,一般需要用到RestTemplate類對象
package hdk.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
【microcloud-consumer】新建一個controller,負責使用RestTemplate調用遠程的product服務
package hdk.controller;
import hdk.vo.Product;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {
public static final String PRODUCT_GET_URL = "http://localhost:8080/prodcut/get/";
public static final String PRODUCT_LIST_URL="http://localhost:8080/prodcut/list/";
public static final String PRODUCT_ADD_URL = "http://localhost:8080/prodcut/add/";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/product/get")
public Object getProduct(long id) {
Product product = restTemplate.getForObject(PRODUCT_GET_URL + id, Product.class);
return product;
}
@RequestMapping("/product/list")
public Object listProduct() {
List<Product> list = restTemplate.getForObject(PRODUCT_LIST_URL, List.class);
return list;
}
@RequestMapping("/product/add")
public Object addPorduct(Product product) {
Boolean result = restTemplate.postForObject(PRODUCT_ADD_URL, product, Boolean.class);
return result;
}
}
【microcloud-consumer】編寫啓動類
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
調用測試
新增:http://localhost/consumer/product/add?productName=lison
列表查詢:http://localhost/consumer/product/list
獲得單個數據:http://localhost/consumer/product/get?id=1
SpringSecurity
前面使用了RestTemplate進行遠程接口調用,但要注意,這些Rest服務最終都可能暴露在公網的,任何人都可能調用,如果你的Rest服務屬於一些私密信息,這樣會導致信息的泄露。
如果想進行安全方面的處理,首先要在服務的提供方上進行處理。
【microcloud-provider-product】修改pom文件,追加 SpringSecurity 相關依賴信息
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
【microcloud-provider-product】修改application.yml配置文件,進行安全的用戶名配置
spring:
security:
user:
name: admin # 認證用戶名
password: hdk # 認證密碼
roles:
- USER # 授權角色
在項目中訪問rest接口,localhost:8080/product/list,這個時候會要求先輸入用戶名以及密碼才能允許訪問
服務消費方處理
【microcloud-consumer】 修改RestConfig配置類,在裏面添加 HttpHeaders 的配置信息
package cn.hdk.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.Base64;
@Configuration
public class RestConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public HttpHeaders getHeaders() { // 要進行一個Http頭信息配置
HttpHeaders headers = new HttpHeaders(); // 定義一個HTTP的頭信息
String auth = "admin:hdk"; // 認證的原始信息
byte[] encodedAuth = Base64.getEncoder()
.encode(auth.getBytes(Charset.forName("US-ASCII"))); // 進行一個加密的處理
String authHeader = "Basic " + new String(encodedAuth);
headers.set("Authorization", authHeader);
return headers;
}
}
【microcloud-consumer】 修改ConsumerProductController,在進行服務端調用的時候加上這個頭信息
package hdk.controller;
import hdk.vo.Product;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {
public static final String PRODUCT_GET_URL = "http://localhost:8080/prodcut/get/";
public static final String PRODUCT_LIST_URL="http://localhost:8080/prodcut/list/";
public static final String PRODUCT_ADD_URL = "http://localhost:8080/prodcut/add/";
@Resource
private RestTemplate restTemplate;
@Resource
private HttpHeaders httpHeaders;
@RequestMapping("/product/get")
public Object getProduct(long id) {
Product product = restTemplate.exchange(PRODUCT_GET_URL + id,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), Product.class).getBody();
return product;
}
@RequestMapping("/product/list")
public Object listProduct() {
List<Product> list = restTemplate.exchange(PRODUCT_LIST_URL,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), List.class).getBody();
return list;
}
@RequestMapping("/product/add")
public Object addPorduct(Product product) {
Boolean result = restTemplate.exchange(PRODUCT_ADD_URL, HttpMethod.POST,new HttpEntity<Object>(product,httpHeaders), Boolean.class).getBody();
return result;
}
}
調用測試
新增:http://localhost/consumer/product/add?productName=lison
列表查詢:http://localhost/consumer/product/list
獲得單個數據:http://localhost/consumer/product/get?id=1
microcloud-security模塊
現在服務提供方只有一個Product服務,但真實的項目開發中必然有多個服務提供方,絕大多數情況下,這些服務都會用到安全驗證,而且密碼也會一樣,如果每個服務都單獨維護,每次密碼變動改動都會很大,所以應該單獨建立一個安全驗證的模塊
創建一個microcloud-security模塊,修改其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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>1.0.0</version>
<artifactId>microcloud-security</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
【springcloud】修改父工程pom文件,把相應的版本依賴加到裏面
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-security</artifactId>
<version>1.0.0</version>
</dependency>
【microcloud-security】建立一個統一的安全配置類,這個類負責用戶以及密碼相關的配置
package hdk.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("root").password(new BCryptPasswordEncoder().encode("hdk")).roles("USER").
and().withUser("admin").password(new BCryptPasswordEncoder().encode("hdk")).roles("USER", "ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().anyRequest()
.fullyAuthenticated();
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
【microcloud-provider-product】修改pom文件,刪除spring-boot-starter-security的依賴信息,並加入自己定義的microcloud-security依賴
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-security</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-security</artifactId>
</dependency>
【microcloud-provider-product】修改application.yml,刪除與安全相關的配置項。
# security:
# user:
# roles:
# - USER # 授權角色
# name: root
# password: hdk
調用測試
新增:http://localhost/consumer/product/add?productName=lison
列表查詢:http://localhost/consumer/product/list
獲得單個數據:http://localhost/consumer/product/get?id=1
Eureka服務註冊與發現
Eureka 服務端
新建一個microcloud-eureka模塊,這模塊做的事情非常簡單,既啓動Eureka的服務端,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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-eureka</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-eureka】修改application.yml文件,在裏面配置eureka相關信息
server:
port: 7001
eureka:
instance: # eureak實例定義
hostname: localhost # 定義 Eureka 實例所在的主機名稱
【microcloud-eureka】新增Eureka啓動類,增加Eureka服務端註解
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
在瀏覽器上執行
http://localhost:7001/
服務提供方註冊到Eureka
【microcloud-provider-product】修改pom文件,增加eureka客戶端相關信息
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
【microcloud-provider-product】修改application.yml配置文件,在者個文件中定義要註冊的eureka服務的地址
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://localhost:7001/eureka
【microcloud-provider-product】修改啓動類,在這個類上增加eureka客戶端的註解信息
package hdk;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@MapperScan("cn.hdk.mapper")
@EnableEurekaClient
public class ProductApp{
public static void main(String[] args) {
SpringApplication.run(ProductApp.class,args);
}
}
啓動後發現Application的名字是UNKNOWN,爲此應該爲這單獨取一個名字
【microcloud-provider-product】修改application.yml配置文件,爲這個微服務起一個名字
spring:
application:
name: microcloud-provider-product
【microcloud-provider-product】修改application.yml配置文件,追加主機名稱的顯示:
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://localhost:7001/eureka
instance:
instance-id: microcloud-provider-product
【microcloud-provider-product】修改application.yml配置文件
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://localhost:7001/eureka
instance:
instance-id: microcloud-provider-product
prefer-ip-address: true #顯示IP
【microcloud-provider-product】如果想看狀態信息需要增加actuator模塊,這一塊的內容已經在講springboot的時候講過,修改pom文件,增加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
【microcloud-provider-product】修改application.yml文件,追加info相關配置
info:
app.name: microcloud-provider-product
company.name: hdk
build.artifactId: $project.artifactId$
build.modelVersion: $project.modelVersion$
注意:由於在yml文件中使用了$,這個時候啓動是會報錯的,因此還需要一個maven-resources-plugin插件的支持
【microcloud】在父工程增加插件,修改pom文件
<build>
<finalName>microcloud</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimiter>$</delimiter>
</delimiters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${jdk.version}</source><!-- 源代碼使用的開發版本 -->
<target>${jdk.version}</target><!-- 需要生成的目標class文件的編譯版本 -->
</configuration>
</plugin>
</plugins>
</build>
啓動後:
另外在關閉【microcloud-provider-product】項目後,刷新eureka發現項目還在,隔一段時間後會發現
這其實就是觸發了安全模式
【microcloud-eureka】設置服務的清理間隔時間,修改application.yml文件
server:
port: 7001
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
instance: # eureak實例定義
hostname: localhost # 定義 Eureka 實例所在的主機名稱
【microcloud-provider-product】修改application.yml配置
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://localhost:7001/eureka
instance:
instance-id: microcloud-provider-product
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
由於所有的服務都註冊到了 Eureka 之中
這樣如果配置了“lease-expiration-duration-in-seconds”此選項,
表示距離上一次發送心跳之後等待下一次發送心跳的間隔時間,如果超過了此間隔時間,則認爲該微服務已經宕機了。
【microcloud-provider-product】對於註冊到 Eureka 上的服務,可以通過發現服務來獲取一些服務信息,修改ProductController,增加一個方法
package hdk.controller;
import cn.hdk.service.IProductService;
import cn.hdk.vo.Product;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("/prodcut")
public class ProductController {
@Resource
private IProductService iProductService;
@Resource
private DiscoveryClient client ; // 進行Eureka的發現服務
@RequestMapping(value="/get/{id}")
public Object get(@PathVariable("id") long id) {
return this.iProductService.get(id) ;
}
@RequestMapping(value="/add")
public Object add(@RequestBody Product product) {
return this.iProductService.add(product) ;
}
@RequestMapping(value="/list")
public Object list() {
return this.iProductService.list() ;
}
@RequestMapping("/discover")
public Object discover() { // 直接返回發現服務信息
return this.client ;
}
}
【microcloud-provider-product】修改ProductApp, 在主程序中啓用發現服務項
package hdk;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@MapperScan("cn.hdk.mapper")
@EnableEurekaClient
@EnableDiscoveryClient
public class ProductApp{
public static void main(String[] args) {
SpringApplication.run(ProductApp.class,args);
}
}
訪問:localhost:8080/prodcut/discover
Eureka 安全機制
一般情況下Eureka 和服務的提供註冊者都會在一個內網環境中,但免不了在某些項目中需要讓其他外網的服務註冊到Eureka,這個時候就有必要讓Eureka增加一套安全認證機制了,讓所有服務提供者通過安全認證後才能註冊進來
【microcloud-eureka】修改pom文件,引入SpringSecurity的依賴包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
【microcloud-eureka】 修改application.yml文件,增加用戶、密碼驗證
server:
port: 7001
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://admin:hdk@localhost:7001/eureka
instance: # eureak實例定義
hostname: localhost # 定義 Eureka 實例所在的主機名稱
spring:
security:
user:
name: admin
password: hdk
【microcloud-provider-product】修改application.yml文件,增加驗證信息
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://admin:hdk@localhost:7001/eureka
instance:
instance-id: microcloud-provider-product
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
【microcloud-eureka】新增配置類EurekaSecurityConfig,重寫configure方法,把csrf劫持關閉
package hdk;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class EurekaSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
super.configure(http);
}
}
HA 高可用
現在的Eureka還是單節點的情況,如果Eureka出現了錯誤,將會導致整個集羣無法繼續使用,這個時候就需要考慮Eureka的高可用了。
現在需要3個eureka ,每個eureka都需要配置hostname,所有先修改hosts文件內容如下
127.0.0.1 eureka1
127.0.0.1 eureka2
127.0.0.1 eureka3
【microcloud-eureka】爲了方便操作,講microcloud-eureka項目複製兩份,分別複製爲【microcloud-eureka2】、 【microcloud-eureka2】
【microcloud-eureka】修改application.yml配置文件,修改端口以及註冊位置
server:
port: 7001
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
service-url:
#defaultZone: http://admin:hdk@localhost:7001/eureka
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance: # eureak實例定義
hostname: eureka1 # 定義 Eureka 實例所在的主機名稱
spring:
security:
user:
name: admin
password: hdk
【microcloud-eureka2】修改application.yml配置文件
server:
port: 7002
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
service-url:
#defaultZone: http://admin:hdk@localhost:7001/eureka
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance: # eureak實例定義
hostname: eureka2 # 定義 Eureka 實例所在的主機名稱
spring:
security:
user:
name: admin
password: hdk
【microcloud-eureka3】修改application.yml配置文件
server:
port: 7003
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
service-url:
#defaultZone: http://admin:hdk@localhost:7001/eureka
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance: # eureak實例定義
hostname: eureka3 # 定義 Eureka 實例所在的主機名稱
spring:
security:
user:
name: admin
password: hdk
啓動eureka,eureka2,eureka3,進入服務的後臺查看副本
登陸http://localhost:7001/
【microcloud-provider-product】修改application.yml配置文件,配置多臺enreka的註冊
server:
port: 8080
mybatis:
mapper-locations: # 所有的mapper映射文件
- classpath:mapping/*.xml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 配置當前要使用的數據源的操作類型
driver-class-name: com.mysql.cj.jdbc.Driver # 配置MySQL的驅動程序類
url: jdbc:mysql://localhost:3306/springcloud?serverTimezone=GMT%2B8 # 數據庫連接地址
username: root # 數據庫用戶名
password: root1234% # 數據庫連接密碼
application:
name: microcloud-provider-product
# security:
# user:
# roles:
# - USER # 授權角色
# name: root
# password: hdk
logging:
level:
cn.hdk.mapper: debug
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
#defaultZone: http://admin:hdk@localhost:7001/eureka
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance:
instance-id: microcloud-provider-product
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
info:
app.name: microcloud-provider-product
company.name: hdk
build.artifactId: $project.artifactId$
build.modelVersion: $project.modelVersion$
打包發佈
在項目中,需要講Eureka發佈到具體服務器上進行執行,打包部署其實和springboot裏面講的大同小異和properties文件稍微有點不同,對於properties文件,不同的環境會有不同的配置文件比如application-dev.properties,application-test.properties,application-pro.properties等
但如果是yml文件,所有的的配置都再同一個yml文件中
【microcloud-eureka】修改application.yml文件
spring:
profiles:
active:
- dev-7001
---
server:
port: 7001
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance: # eureak實例定義
hostname: eureka1 # 定義 Eureka 實例所在的主機名稱
spring:
profiles: dev-7001
security:
user:
name: admin
password: hdk
application:
name: microcloud-eureka
---
server:
port: 7002
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance: # eureak實例定義
hostname: eureka2 # 定義 Eureka 實例所在的主機名稱
spring:
profiles: dev-7002
security:
user:
name: admin
password: hdk
application:
name: microcloud-eureka2
---
server:
port: 7003
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance: # eureak實例定義
hostname: eureka3 # 定義 Eureka 實例所在的主機名稱
spring:
profiles: dev-7003
security:
user:
name: admin
password: hdk
application:
name: microcloud-eureka3
【microcloud-eureka】添加一個打包插件,修改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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-eureka</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<build>
<finalName>eureka-server</finalName>
<plugins>
<plugin> <!-- 該插件的主要功能是進行項目的打包發佈處理 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <!-- 設置程序執行的主類 -->
<mainClass>cn.hdk.EurekaApp</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
【microcloud-eureka】 在pom文件所在目錄
mvn clean install package
接下來就可以在項目的編譯目錄發現
eureka-server.jar 文件
採用默認的方式執行 eureka-server.jar那麼此時將運行在 7001 端口上:java -jar eureka-server.jar
運行其它的兩個 profile 配置:
· 運行“dev-7002”profile:java -jar eureka-server.jar --spring.profiles.active=dev-7002;
· 運行“dev-7003”profile:java -jar eureka-server.jar --spring.profiles.active=dev-7003
Ribbon負載均衡
現在服務提供方已經可以通過Eureka進行註冊了,但對於服務的消費者,目前並沒有處理,對於服務的消費方,也應該連接上eureka,進行服務的獲取,這個時候就應該使用Ribbon這個組件了
ribbon對應的pom文件如下
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
Ribbon基本使用
【microcloud-consumer】 修改pom文件,增加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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-consumer</artifactId>
<dependencies>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-consumer】 修改RestConfig配置類,在獲取RestTemplate對象的時候加入Ribbon的配置信息
package cn.hdk.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.Base64;
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public HttpHeaders getHeaders() { // 要進行一個Http頭信息配置
HttpHeaders headers = new HttpHeaders(); // 定義一個HTTP的頭信息
String auth = "root:hdk"; // 認證的原始信息
byte[] encodedAuth = Base64.getEncoder()
.encode(auth.getBytes(Charset.forName("US-ASCII"))); // 進行一個加密的處理
String authHeader = "Basic " + new String(encodedAuth);
headers.set("Authorization", authHeader);
return headers;
}
}
【microcloud-consumer】 修改RestConfig配置類,在獲取RestTemplate對象的時候加入Ribbon的配置信息```
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
【microcloud-consumer】修改項目啓動類,增加Eureka客戶端的配置註解
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
【microcloud-consumer】 修改ConsumerProductController控制器
現在在eureka中註冊的服務名稱都是大寫字母:
MICROCLOUD-PROVIDER-PRODUCT
package hdk.controller;
import hdk.vo.Product;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {
public static final String PRODUCT_GET_URL = "http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/get/";
public static final String PRODUCT_LIST_URL="http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/list/";
public static final String PRODUCT_ADD_URL = "http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/add/";
@Resource
private RestTemplate restTemplate;
@Resource
private HttpHeaders httpHeaders;
@RequestMapping("/product/get")
public Object getProduct(long id) {
Product product = restTemplate.exchange(PRODUCT_GET_URL + id,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), Product.class).getBody();
return product;
}
@RequestMapping("/product/list")
public Object listProduct() {
List<Product> list = restTemplate.exchange(PRODUCT_LIST_URL,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), List.class).getBody();
return list;
}
@RequestMapping("/product/add")
public Object addPorduct(Product product) {
Boolean result = restTemplate.exchange(PRODUCT_ADD_URL, HttpMethod.POST,new HttpEntity<Object>(product,httpHeaders), Boolean.class).getBody();
return result;
}
}
訪問地址:http://localhost/consumer/product/list
這個時候Ribbon與Eureka已經整合成功
Ribbon負載均衡的實現
通過上面的代碼發現我們用到了一個註解@LoadBalanced,根據這名字大概就能知道Ribbon是可以實現負載均衡的
【microcloud-provider-product】 複製兩份
分別爲【microcloud-provider-product2】與【microcloud-provider-product3】
【springcloud數據庫】複製兩份
分別爲【springcloud2數據庫】【springcloud3數據庫】 裏面分別執行spingcloud數據庫的腳本
【microcloud-provider-product2】修改application.yml文件如下
server:
port: 8081
mybatis:
mapper-locations: # 所有的mapper映射文件
- classpath:mapping/*.xml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 配置當前要使用的數據源的操作類型
driver-class-name: com.mysql.cj.jdbc.Driver # 配置MySQL的驅動程序類
url: jdbc:mysql://localhost:3306/springcloud2?serverTimezone=GMT%2B8 # 數據庫連接地址
username: root # 數據庫用戶名
password: root1234% # 數據庫連接密碼
application:
name: microcloud-provider-product
# security:
# user:
# roles:
# - USER # 授權角色
# name: root
# password: hdk
logging:
level:
hdk.mapper: debug
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
#defaultZone: http://admin:hdk@localhost:7001/eureka
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance:
instance-id: microcloud-provider-product2
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
info:
app.name: microcloud-provider-product2
company.name: hdk
build.artifactId: $project.artifactId$
build.modelVersion: $project.modelVersion$
【microcloud-provider-product3】修改application.yml文件如下
server:
port: 8082
mybatis:
mapper-locations: # 所有的mapper映射文件
- classpath:mapping/*.xml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 配置當前要使用的數據源的操作類型
driver-class-name: com.mysql.cj.jdbc.Driver # 配置MySQL的驅動程序類
url: jdbc:mysql://localhost:3306/springcloud3?serverTimezone=GMT%2B8 # 數據庫連接地址
username: root # 數據庫用戶名
password: root1234% # 數據庫連接密碼
application:
name: microcloud-provider-product
# security:
# user:
# roles:
# - USER # 授權角色
# name: root
# password: hdk
logging:
level:
cn.hdk.mapper: debug
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
#defaultZone: http://admin:hdk@localhost:7001/eureka
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance:
instance-id: microcloud-provider-product3
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
info:
app.name: microcloud-provider-product3
company.name: hdk
build.artifactId: $project.artifactId$
build.modelVersion: $project.modelVersion$
分別啓動3個服務提供方,訪問
http://localhost:8080/product/get/1
http://localhost:8081/product/get/1
http://localhost:8082/product/get/1
確認3個服務是能正確提供訪問的
【microcloud-consumer】啓動
訪問:http://localhost/consumer/product/list
自定義Ribbon路由
前面已經使用Ribbon實現了路由,通過測試,也不難發現默認Ribbon使用的路由策略是輪詢,可以看下源代碼BaseLoadBalancer
全局路由配置
這種負載均衡的策略其實也是可以由用戶來修改的,如果想要去修改,可以使用自定義的LoadBalance
【microcloud-consumer】 修改RestConfig
package hdk.config;
import com.netflix.loadbalancer.IRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.Base64;
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public HttpHeaders getHeaders() { // 要進行一個Http頭信息配置
HttpHeaders headers = new HttpHeaders(); // 定義一個HTTP的頭信息
String auth = "root:hdk"; // 認證的原始信息
byte[] encodedAuth = Base64.getEncoder()
.encode(auth.getBytes(Charset.forName("US-ASCII"))); // 進行一個加密的處理
String authHeader = "Basic " + new String(encodedAuth);
headers.set("Authorization", authHeader);
return headers;
}
@Bean
public IRule ribbonRule() { // 其中IRule就是所有規則的標準
return new com.netflix.loadbalancer.RandomRule(); // 隨機的訪問策略
}
}
這個時候重啓測試發現,默認的路由規則已經變成了隨機
單獨設置某個Ribbon的路由
有時候,某個消費者可能需要訪問多個多個服務提供方,而希望每個服務提供方提供的路由規則並不相同,這個時候就不能讓Spring掃描到IRULE,需要通過@RibbonClient 來指定服務於配置的關係
【microcloud-consumer】 修改RestConfig,刪除IRULE
package cn.hdk.config;
import com.netflix.loadbalancer.IRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.Base64;
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public HttpHeaders getHeaders() { // 要進行一個Http頭信息配置
HttpHeaders headers = new HttpHeaders(); // 定義一個HTTP的頭信息
String auth = "root:hdk"; // 認證的原始信息
byte[] encodedAuth = Base64.getEncoder()
.encode(auth.getBytes(Charset.forName("US-ASCII"))); // 進行一個加密的處理
String authHeader = "Basic " + new String(encodedAuth);
headers.set("Authorization", authHeader);
return headers;
}
// @Bean
// public IRule ribbonRule() { // 其中IRule就是所有規則的標準
// return new com.netflix.loadbalancer.RandomRule(); // 隨機的訪問策略
// }
}
【microcloud-consumer】新增一個路由規則的配置類,注意這個類不應該放到SpringCloud掃描不到的位置,否則又回變成全局的IRULE,所以這個時候應該單獨使用一個新的包,着個包和啓動並不在同一個包下
package hdk.config;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
public class RibbonConfig {
@Bean
public IRule ribbonRule() { // 其中IRule就是所有規則的標準
return new com.netflix.loadbalancer.RandomRule(); // 隨機的訪問策略
}
}
【microcloud-consumer】 修改啓動類,使用@RibbonClient指定配置類
package hdk;
import hdkconfig.RibbonConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name ="MICROCLOUD-PROVIDER-PRODUCT" ,configuration = RibbonConfig.class)
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
這裏的name 只服務的名稱,如果需要有多個服務提供方,這個時候可以使用@RibbonClients進行配置
服務提供方的信息獲取
在服務的消費方,也是可以獲取到服務提供方的具體信息
【microcloud-consumer】修改ConsumerProductController
package cn.hdk.controller;
import cn.hdk.vo.Product;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {
public static final String PRODUCT_GET_URL = "http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/get/";
public static final String PRODUCT_LIST_URL="http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/list/";
public static final String PRODUCT_ADD_URL = "http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/add/";
@Resource
private RestTemplate restTemplate;
@Resource
private HttpHeaders httpHeaders;
@Resource
private LoadBalancerClient loadBalancerClient;
@RequestMapping("/product/get")
public Object getProduct(long id) {
Product product = restTemplate.exchange(PRODUCT_GET_URL + id,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), Product.class).getBody();
return product;
}
@RequestMapping("/product/list")
public Object listProduct() {
ServiceInstance serviceInstance = this.loadBalancerClient.choose("MICROCLOUD-PROVIDER-PRODUCT") ;
System.out.println(
"【*** ServiceInstance ***】host = " + serviceInstance.getHost()
+ "、port = " + serviceInstance.getPort()
+ "、serviceId = " + serviceInstance.getServiceId());
List<Product> list = restTemplate.exchange(PRODUCT_LIST_URL,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), List.class).getBody();
return list;
}
@RequestMapping("/product/add")
public Object addPorduct(Product product) {
Boolean result = restTemplate.exchange(PRODUCT_ADD_URL, HttpMethod.POST,new HttpEntity<Object>(product,httpHeaders), Boolean.class).getBody();
return result;
}
}
脫離Eureka使用Ribbon
之前所用Ribbon都是從Eureka中獲取服務並通過@LoadBalanced來實現負載均衡的,其實Ribbon也可以脫離Eureka來使用
複製【microcloud-consumer】 成一個新的模塊【microcloud-consumer-ribbon】
【microcloud-consumer-ribbon】 修改pom文件,刪除eureka的依賴添加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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-consumer-ribbon</artifactId>
<dependencies>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-consumer-ribbon】 修改application.yml配置文件
server:
port: 80
ribbon:
eureka:
enabled: false
MICROCLOUD-PROVIDER-PRODUCT:
ribbon:
listOfServers: http://localhost:8080,http://localhost:8081,http://localhost:8082
【microcloud-consumer-ribbon】 修改 RestConfig,刪除@LoadBalanced註解
package hdk.config;
import com.netflix.loadbalancer.IRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.Base64;
@Configuration
public class RestConfig {
@Bean
//@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public HttpHeaders getHeaders() { // 要進行一個Http頭信息配置
HttpHeaders headers = new HttpHeaders(); // 定義一個HTTP的頭信息
String auth = "root:hdk"; // 認證的原始信息
byte[] encodedAuth = Base64.getEncoder()
.encode(auth.getBytes(Charset.forName("US-ASCII"))); // 進行一個加密的處理
String authHeader = "Basic " + new String(encodedAuth);
headers.set("Authorization", authHeader);
return headers;
}
}
【microcloud-consumer-ribbon】修改ConsumerProductController,修改服務的調用URI
package hdk.controller;
import cn.hdk.vo.Product;
import cn.xiangxue.config.RibbonConfig;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.net.URI;
import java.util.List;
@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {
public static final String PRODUCT_TOPIC = "MICROCLOUD-PROVIDER-PRODUCT";
@Resource
private RestTemplate restTemplate;
@Resource
private HttpHeaders httpHeaders;
@Resource
private LoadBalancerClient loadBalancerClient;
@RequestMapping("/product/list")
public Object listProduct() {
ServiceInstance serviceInstance = this.loadBalancerClient.choose(PRODUCT_TOPIC) ;
System.out.println(
"【*** ServiceInstance ***】host = " + serviceInstance.getHost()
+ "、port = " + serviceInstance.getPort()
+ "、serviceId = " + serviceInstance.getServiceId());
URI uri = URI.create(String.format("http://%s:%s/prodcut/list/" ,
serviceInstance.getHost(), serviceInstance.getPort()));
List<Product> list = restTemplate.exchange(uri,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), List.class).getBody();
return list;
}
}
【microcloud-consumer-ribbon】啓動
訪問:http://localhost/consumer/product/list
Feign接口服務
前面已經學習了Ribbon,從Eureka獲取服務的實例在通過RestTemplate調用,並轉換成需要的對象
List
list = restTemplate.exchange(PRODUCT_LIST_URL,HttpMethod.GET,new HttpEntity
可以發現所有的數據調用和轉換都是由用戶直接來完成的,我們可能不想直接訪問Rest接口,如果轉換回來的直接是對象而不需要直接使用RestTemplate進行轉換就好了,這個時候就需要使用Feign了
Feign基本使用
複製【microcloud-consumer】 成一個新的模塊【microcloud-consumer-feign】
【microcloud-consumer-feign】修改pom文件,增加對feign的支持
<?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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-consumer-feign</artifactId>
<dependencies>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-service】,新建立一個microcloud-service模塊,這個模塊專門定義客戶端的調用接口
【microcloud-service】,修改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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-service</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-service】如果要通過Feign進行遠程調用,依然需要安全服務提供方的認證問題,不過在feign裏面已經集成了這塊功能
package hdk.feign;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignClientConfig {
@Bean
public BasicAuthRequestInterceptor getBasicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("admin", "hdk");
}
}
【microcloud-service】 新建一個IProductClientService接口
package cn.hdk.service;
import cn.hdk.feign.FeignClientConfig;
import cn.hdk.vo.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@FeignClient(name = "MICROCLOUD-PROVIDER-PRODUCT",configuration = FeignClientConfig.class)
public interface IProductClientService {
@RequestMapping("/product/get/{id}")
public Product getProduct(@PathVariable("id")long id);
@RequestMapping("/product/list")
public List<Product> listProduct() ;
@RequestMapping("/product/add")
public boolean addPorduct(Product product) ;
}
【microcloud-consumer-feign】 修改pom文件,引入microcloud-service 包
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-service</artifactId>
</dependency>
【microcloud-consumer-feign】 由於microcloud-service裏面已經做了安全驗證,並且後面並不直接使用RestTemplate ,刪除RestConfig.java類
【microcloud-consumer-feign】 修改ConsumerProductController,這個時候直接使用microcloud-service定義的服務就可以了
package hdk.controller;
import hdk.service.IProductClientService;
import cn.hdk.vo.Product;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {
@Resource
private IProductClientService iProductClientService;
@RequestMapping("/product/get")
public Object getProduct(long id) {
return iProductClientService.getProduct(id);
}
@RequestMapping("/product/list")
public Object listProduct() {
return iProductClientService.listProduct();
}
@RequestMapping("/product/add")
public Object addPorduct(Product product) {
return iProductClientService.addPorduct(product);
}
}
【microcloud-consumer-feign】修改程序主類
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients("hdk.service")
public class ConsumerFeignApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerFeignApp.class,args);
}
}
啓動測試:
http://localhost/consumer/product/list
可以做個測試,看下是否真的如此
【microcloud-consumer-feign】修改程序主類
package hdk;
import cn.xiangxue.config.RibbonConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients("cn.hdk.service")
@RibbonClient(name ="MICROCLOUD-PROVIDER-PRODUCT" ,configuration = RibbonConfig.class)
public class ConsumerFeignApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerFeignApp.class,args);
}
}
啓動測試:
http://localhost/consumer/product/list
可以發現,現在的路由規則以及變成了隨機訪問
其他配置
數據壓縮
前面我們已經知道Feign之中最核心的作用就是將Rest服務的信息轉化爲接口,這其中還有其他的一些地方應該要考慮,比如:數據的壓縮
Rest協議更多的傳輸的是文本,JSON或者XML,如果用戶發送的請求很大,這個時候有必要對數據進行壓縮處理,好在feign本身就提供了壓縮的支持
雖然Feign支持壓縮,但默認是不開啓的
再看下FeignClientEncodingProperties,可以根據這裏面的屬性進行相關壓縮的配置
【microcloud-consumer-feign】 修改application.yml配置文件
feign:
compression:
request:
enabled: true
mime-types: # 可以被壓縮的類型
- text/xml
- application/xml
- application/json
min-request-size: 2048 # 超過2048的字節進行壓縮
日誌配置
在構建@FeignClient註解修飾的服務客戶端時,會爲一個客戶端都創建一個feign.Logger實例,可以利用日誌來分析Feign的請求細節,不過默認
【microcloud-consumer-feign】 修改 application.yml配置文件,增加日誌信息
logging:
level:
cn.hdk.service: DEBUG
【microcloud-service】修改FeignClientConfig,開啓日誌輸出
package hdk.feign;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignClientConfig {
@Bean
public Logger.Level getFeignLoggerLevel() {
return feign.Logger.Level.FULL ;
}
@Bean
public BasicAuthRequestInterceptor getBasicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("admin", "hdk");
}
}
小結
當使用 Feign 要通過接口的方法訪問 Rest 服務的時候會根據設置的服務類型發出請求,這個請求是發送給 Eureka
隨後由於配置了授權處理,所以繼續發送授權信息(“Authorization”)
其實在外面使用RestTemplate的時候也是這麼做的,可以對應日誌的加密內容和直接訪問其實是一樣的。
- 在進行服務調用的時候 Feign 融合了 Ribbon 技術,所以也支持有負載均衡的處理
Feign = RestTempate + HttpHeader + Ribbon + Eureka 綜合體,使用feign大大增加了代碼的靈活程度
Hystrix 熔斷機制
在分佈式環境下,微服務之間不可避免的發生互相調用的情況,但是沒有一個系統是能保證自身絕對正確的,在服務的調用過程中,很可能面臨服務失敗的問題,因此需要一個公共組件能夠在服務通過網絡請求訪問其他微服務時,能對服務失效情況下有很強的容錯能力,對微服務提供保護和監控。
Hystrix是netflix的一個開源項目,他能夠在依賴服務失效的情況下,通過隔離系統依賴的方式,防止服務的級聯失敗(服務的雪崩)
對於服務的熔斷機制,其實需要考慮兩種情況
- 服務提供方存活,但調用接口報錯
- 服務提供方本身就出問題了
服務提供方報錯
其實這種情況類似於異常捕獲機制,當出現異常,返回一個通用的接口報文
【microcloud-provider-product】 複製一份成爲【microcloud-provider-product-hystrix】
【microcloud-provider-product-hystrix】修改pom文件,增加 Hystrix依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
【microcloud-provider-product-hystrix】 修改ProductController
package hdk.controller;
import hdk.service.IProductService;
import hdk.vo.Product;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("/product")
public class ProductController {
@Resource
private IProductService iProductService;
@Resource
private DiscoveryClient client ; // 進行Eureka的發現服務
@RequestMapping(value="/get/{id}")
@HystrixCommand(fallbackMethod = "getFallback")
public Object get(@PathVariable("id") long id) {
Product product = this.iProductService.get(id);
if(product == null) {
throw new RuntimeException("該產品已下架!") ;
}
return product;
}
public Object getFallback(@PathVariable("id") long id){
Product product = new Product();
product.setProductName("HystrixName");
product.setProductDesc("HystrixDesc");
product.setProductId(0L);
return product;
}
@RequestMapping(value="/add")
public Object add(@RequestBody Product product) {
return this.iProductService.add(product) ;
}
@RequestMapping(value="/list")
public Object list() {
return this.iProductService.list() ;
}
@RequestMapping("/discover")
public Object discover() { // 直接返回發現服務信息
return this.client ;
}
}
一旦 get()方法上拋出了錯誤的信息,那麼就認爲該服務有問題
會默認使用“@HystrixCommand”註解之中配置好的fallbackMethod 調用類中的指定方法,返回相應數據
【microcloud-provider-product-hystrix】修改啓動類,增加對熔斷的支持
package hdk;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@MapperScan("cn.hdk.mapper")
@EnableEurekaClient
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ProductHystrixApp {
public static void main(String[] args) {
SpringApplication.run(ProductHystrixApp.class,args);
}
}
測試:localhost:8080/product/get/100 訪問
服務器失連
在某些情況下,服務提供方並沒有失效,但可能由於網絡原因,服務的消費方並不能調用到服務接口,在這種情況下,直接在服務的提供方提供熔斷機制依然還是不夠的,這方面的處理需要在服務的消費方進行服務的回退(服務的降級)處理
服務的熔斷:熔斷指的是當服務的提供方不可使用的時候,程序不會出現異常,而會出現本地的操作調用,服務的熔斷是在服務消費方實現的,在斷網情況下服務提供方的任何處理都是沒有意義的。
【microcloud-service】新增一個IProductClientService的失敗調用(降級處理)
package hdk.service.fallback;
import hdk.service.IProductClientService;
import hdk.vo.Product;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class IProductClientServiceFallbackFactory implements FallbackFactory<IProductClientService> {
@Override
public IProductClientService create(Throwable throwable) {
return new IProductClientService() {
@Override
public Product getProduct(long id) {
Product product = new Product();
product.setProductId(999999L);
product.setProductName("feign-hystrixName");
product.setProductDesc("feign-hystrixDesc");
return product;
}
@Override
public List<Product> listProduct() {
return null;
}
@Override
public boolean addPorduct(Product product) {
return false;
}
};
}
}
【microcloud-service】 修改IProductClientService,增加fallback配置
package hdk.service;
import hdk.feign.FeignClientConfig;
import hdk.service.fallback.IProductClientServiceFallbackFactory;
import cn.hdk.vo.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@FeignClient(name = "MICROCLOUD-PROVIDER-PRODUCT",configuration = FeignClientConfig.class,
fallbackFactory = IProductClientServiceFallbackFactory.class)
public interface IProductClientService {
@RequestMapping("/product/get/{id}")
public Product getProduct(@PathVariable("id")long id);
@RequestMapping("/product/list")
public List<Product> listProduct() ;
@RequestMapping("/product/add")
public boolean addPorduct(Product product) ;
}
【microcloud-consumer-feign】 複製一份成爲【microcloud-consumer-hystrix】模塊
【microcloud-consumer-hystrix】 修改application.yml配置文件,啓用hystrix配置
feign:
hystrix:
enabled: true
compression:
request:
enabled: true
mime-types: # 可以被壓縮的類型
- text/xml
- application/xml
- application/json
min-request-size: 2048 # 超過2048的字節進行壓縮
啓動,服務提供者
訪問:http://localhost/consumer/product/get?id=1,能正常訪問
關閉,服務提供者
訪問:http://localhost/consumer/product/get?id=1,也能正常訪問
HystrixDashboard
在hystrix裏面提供一個Dashboard(儀表盤)的功能,他是一種監控的功能,可以利用它來進行整體服務的監控
新建一個模塊【microcloud-consumer-hystrix-dashboard】
【microcloud-consumer-hystrix-dashboard】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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-consumer-hystrix-dashboard</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<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>
</project>
【microcloud-provider-product-hystrix】 pom文件確保裏面有健康檢查模塊
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
【microcloud-consumer-hystrix-dashboard】 修改application.yml配置文件
server:
port: 9001
【microcloud-consumer-hystrix-dashboard】 創建一個啓動類
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApp {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApp.class,args);
}
}
啓動運行:http://localhost:9001/hystrix
【microcloud-provider-product-hystrix】 修改applcation.yml文件
management:
endpoints:
web:
exposure:
include: '*'
【microcloud-provider-product-hystrix】啓動
訪問:localhost:8080/actuator/hystrix.stream
http://localhost:9001/hystrix 填寫信息如下
http://admin:hdk@localhost:8080/actuator/hystrix.stream
這個時候對localhost:8080的訪問都可以被監控到
Turbine
HystrixDashboard 前面已經知道了,它的主要功能是可以對某一項微服務進行監控,但真實情況下,不可能只對某一個服務進行監控,更多的是對很多服務進行一個整體的監控,這個時候就需要使用到turbine來完成了。
爲了演示監控多個服務模塊,這個時候新建一個模塊【microcloud-provider-user-hystrix】,爲簡單起見,這個模塊並不連接數據庫,也不做安全控制。
【microcloud-provider-user-hystrix】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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-provider-user-hystrix</artifactId>
<dependencies>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-api】新增一個VO類:Users
package cn.hdk.vo;
import java.io.Serializable;
public class Users implements Serializable {
private String name;
private int age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
【microcloud-provider-user-hystrix】 新建一個UserController
package hdk.controller;
import hdk.vo.Users;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class UserController {
@RequestMapping("/get/{name}")
@HystrixCommand
public Object get(@PathVariable("name")String name) {
Users users = new Users();
users.setName(name);
users.setAge(18);
users.setSex("F");
return users;
}
}
【microcloud-provider-user-hystrix】新增啓動類
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableCircuitBreaker
@EnableEurekaClient
public class UsersApp {
public static void main(String[] args) {
SpringApplication.run(UsersApp.class,args);
}
}
【microcloud-provider-user-hystrix】修改application.yml配置文件
server:
port: 8090
spring:
application:
name: microcloud-provider-users
logging:
level:
hdk.mapper: debug
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance:
instance-id: microcloud-provider-users
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
info:
app.name: microcloud-provider-users
company.name: hdk
build.artifactId: $project.artifactId$
build.modelVersion: $project.modelVersion$
management:
endpoints:
web:
exposure:
include: '*'
啓動後:
訪問地址:http://localhost:8090/users/get/hdk
hystrix監控地址:http://localhost:8090/actuator/hystrix.stream
前面準備工作完成後,如果想要實現 turbine 的配置,準備一個turbine模塊
新增【microcloud-consumer-turbine】模塊,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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-consumer-turbine</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-consumer-turbine】修改application.yml配置文件
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.turbine.EnableTurbine;
@SpringBootApplication
@EnableTurbine
public class TurbineApp {
public static void main(String[] args) {
SpringApplication.run(TurbineApp.class,args);
}
}
turbine監控地址:
啓動Dashboard: http://localhost:9001/hystrix
在Dashboard裏面填上 turbine監控地址
這時還會報錯。
【microcloud-security】如果現在需要turbine進行加密服務的訪問,那麼只能折衷處理,讓訪問/actuator/hystrix.stream與/turbine.stream這兩個地址的時候不需要用戶密碼驗證
【microcloud-security】 修改WebSecurityConfiguration
package cn.hdk.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("root").password(new BCryptPasswordEncoder().encode("hdk")).roles("USER").
and().withUser("admin").password(new BCryptPasswordEncoder().encode("hdk")).roles("USER", "ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().anyRequest()
.fullyAuthenticated();
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/actuator/hystrix.stream","/turbine.stream") ;
}
}
turbine監控地址:http://localhost:9101/turbine.stream
啓動Dashboard: http://localhost:9001/hystrix
在Dashboard裏面填上 turbine監控地址
刷新:
http://localhost:8080/prodcut/get/1
http://localhost:8090/users/get/1
Zuul路由
前面所有的微服務都是通過Eureka找到的,但是在很多開發中爲了規範微服務的使用,提供有一個處理控制器Zuul
Zuul其實是一個API網關,類似於設計模式裏面的Facade門面模式,他的存在就像是整個微服務的門面,所有的外部客戶端訪問都需要經過它來進行調度與過濾
基本使用
新建立一個模塊【microcloud-zuul-gateway】
【microcloud-zuul-gateway】 的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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-zuul-gateway</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-zuul-gateway】修改application.yml文件
server:
port: 9501
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
register-with-eureka: false
spring:
application:
name: microcloud-zuul-gateway
【microcloud-zuul-gateway】 創建啓動類
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.web.bind.annotation.RequestMapping;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApp {
public static void main(String[] args) {
SpringApplication.run(ZuulApp.class,args);
}
}
Zuul配置路由
前面以及簡單的使用了zuul,但你會發現訪問地址還必須知道程序的名稱,如果不知道這個名稱是無法訪問的,但如果讓用戶知道了這名稱,那麼使用zuul就是去它的實際意義的,我們可以通過名稱直接調用
既然是使用代理,那麼代理的功能就是不能讓用戶看到真實的操作,屏蔽真實的調用地址,這個時候就需要自己增加zuul的路由規則配置了。
【microcloud-zuul-gateway】修改application.yml配置文件,增加路由配置
zuul:
routes:
microcloud-provider-users: /users-proxy/**
這個時候就可以通過/users-proxy 來訪問microcloud-provider-users服務
http://localhost:9501/users-proxy/users/get/1
但是還會發現,雖然現在以及開啓了路由訪問的支持,但依然通過應用程序的名稱還是能訪問
http://localhost:9501/microcloud-provider-users/users/get/1
【microcloud-zuul-gateway】修改application.yml文件,忽略掉用戶服務的名稱
zuul:
routes:
microcloud-provider-users: /users-proxy/**
ignored-services:
microcloud-provider-users
做完後,就可以進行代理的安全使用,但真實情況下,一般會有很多微服務,如果完全按照上面的配置方式會非常的麻煩,所有最加到的做法是可以採用一個通配符“*”的模式來統一完成。
【microcloud-zuul-gateway】修改application.yml文件
zuul:
routes:
microcloud-provider-users: /users-proxy/**
ignored-services:
"*"
除開上面這一種訪問模式以外,在zuul中還有另外一種配置方式
【microcloud-zuul-gateway】修改application.yml文件
zuul:
routes:
users.path: /users-proxy/**
users.serviceId: microcloud-provider-users
ignored-services:
"*"
其中在配置文件中出現的users其實是一個邏輯名稱,這個名稱主要作用是將path與serviceId綁定在一起
【microcloud-zuul-gateway】如果說不想通過eureka進行訪問,對於zuul來說也是可以實現的,但是在真實的開發環境中,基本不會使用
zuul:
routes:
users:
path: /users-proxy/**
serviceId: microcloud-provider-users
users2:
path: /users2-proxy/**
url: http://localhost:8090/
ignored-services:
"*"
訪問:http://localhost:9501/users2-proxy/users/get/1
【microcloud-zuul-gateway】 設置公共前綴
zuul:
routes:
users:
path: /users-proxy/**
serviceId: microcloud-provider-users
users2:
path: /users2-proxy/**
url: http://localhost:8090/
ignored-services:
"*"
prefix: /hdk-api
一旦設置了公共前綴,所以的訪問路徑都要在前面加上前綴
http://localhost:9501/hdk-api/users-proxy/users/get/1
http://localhost:9501/hdk-api/users2-proxy/users/get/1
zuul 過濾訪問
其實zuul的功能本質上就是一個代理操作,類似於nginx,但是在真實的使用中,所有的微服務一點都有增加的認證信息,那麼就必須在其訪問之前追加認證的頭部操作,這樣的功能需要通過zuul的過去操作完成。
【microcloud-zuul-gateway】 修改application.yml配置,增加產品微服務
zuul:
routes:
users:
path: /users-proxy/**
serviceId: microcloud-provider-users
users2:
path: /users2-proxy/**
url: http://localhost:8090/
product:
path: /product-proxy/**
serviceId: microcloud-provider-product
ignored-services:
"*"
prefix: /hdk-api
這樣直接訪問:http://localhost:9501/hdk-api/product-proxy/prodcut/get/1
這樣是訪問不到的
【microcloud-zuul-gateway】追加過濾處理
package hdk.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import java.nio.charset.Charset;
import java.util.Base64;
public class AuthorizedRequestFilter extends ZuulFilter{
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext() ; // 獲取當前請求的上下文
String auth = "admin:hdk"; // 認證的原始信息
byte[] encodedAuth = Base64.getEncoder()
.encode(auth.getBytes(Charset.forName("US-ASCII"))); // 進行一個加密的處理
String authHeader = "Basic " + new String(encodedAuth);
currentContext.addZuulRequestHeader("Authorization", authHeader);
return null;
}
}
其中filterType爲過濾的類型
在進行Zuul過濾的時候可以設置其過濾執行的位置,那麼此時有如下幾種類型:
pre:在請求發出之前執行過濾,如果要進行訪問,肯定在請求前設置頭信息
route:在進行路由請求的時候被調用;
post:在路由之後發送請求信息的時候被調用;
error:出現錯誤之後進行調用
【microcloud-zuul-gateway】建立一個配置程序類
package hdk.config;
import cn.hdk.filter.AuthorizedRequestFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ZuulConfig {
@Bean
public AuthorizedRequestFilter getAuthorizedRequestFilter() {
return new AuthorizedRequestFilter() ;
}
}
這個時候訪問:
http://localhost:9501/hdk-api/product-proxy/prodcut/get/1
http://localhost:9501/hdk-api/users-proxy/users/get/1
這兩個服務都能正常訪問了。
Zuul安全訪問
作爲所有接口的統一門面,zuul也是可以進行加密訪問的
【microcloud-zuul-gateway】修改pom文件,增加安全訪問模塊
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
【microcloud-zuul-gateway】修改application.yml配置文件,增加用戶配置
spring:
application:
name: microcloud-zuul-gateway
security:
user:
name: admin
password: hdk
再訪問http://localhost:9501/hdk-api/users-proxy/users/get/1
這個時候就需要輸入用戶名密碼了
Feign訪問Zuul
前面學習feign的時候確實已經知道,他其實是去eureka中獲取服務地址的,如果想使用feign來訪問zuul,首先就應該讓zuul註冊到eureka中
【microcloud-zuul-gateway】 修改application.yml文件
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
instance:
instance-id: microcloud-zuul-gateway
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
【microcloud-service】現在所有的服務要通過zuul的代理進行訪問,新增接口
package .hdk.service;
import hdk.feign.FeignClientConfig;
import hdk.service.fallback.IProductClientServiceFallbackFactory;
import hdk.service.fallback.IZUUlClientServiceallbackFactory;
import hdk.vo.Product;
import hdk.vo.Users;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@FeignClient(name = "MICROCLOUD-ZUUL-GATEWAY",configuration = FeignClientConfig.class,
fallbackFactory = IZUUlClientServiceallbackFactory.class)
public interface IZUUlClientService {
@RequestMapping("/hdk-api/product-proxy/product/get/{id}")
public Product getProduct(@PathVariable("id")long id);
@RequestMapping("/hdk-api/product-proxy/product/list")
public List<Product> listProduct() ;
@RequestMapping("/hdk-api/product-proxy/product/add")
public boolean addPorduct(Product product) ;
@RequestMapping("/hdk-api/users-proxy/users/get/{name}")
public Users getUsers(@PathVariable("name")String name);
}
新增IZUUlClientServiceallbackFactory,在Zuul由於出現網絡問題失去聯繫後進行容錯處理
package.hdk.service.fallback;
import hdk.service.IProductClientService;
import hdk.service.IZUUlClientService;
import hdk.vo.Product;
import hdk.vo.Users;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class IZUUlClientServiceallbackFactory implements FallbackFactory<IZUUlClientService> {
@Override
public IZUUlClientService create(Throwable throwable) {
return new IZUUlClientService() {
@Override
public Product getProduct(long id) {
Product product = new Product();
product.setProductId(999999L);
product.setProductName("feign-zuulName");
product.setProductDesc("feign-zuulDesc");
return product;
}
@Override
public List<Product> listProduct() {
return null;
}
@Override
public boolean addPorduct(Product product) {
return false;
}
@Override
public Users getUsers(String name) {
Users user = new Users();
user.setSex("F");
user.setAge(17);
user.setName("zuul-fllback:"+name);
return user;
}
};
}
}
【microcloud-consumer-hystrix】 修改ConsumerProductController,增加一個新的方法,訪問接口
package hdk.controller;
import hdk.service.IProductClientService;
import hdk.service.IZUUlClientService;
import hdk.vo.Product;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {
@Resource
private IProductClientService iProductClientService;
@Resource
private IZUUlClientService izuUlClientService;
@RequestMapping("/product/get")
public Object getProduct(long id) {
return iProductClientService.getProduct(id);
}
@RequestMapping("/product/list")
public Object listProduct() {
return iProductClientService.listProduct();
}
@RequestMapping("/product/add")
public Object addPorduct(Product product) {
return iProductClientService.addPorduct(product);
}
@RequestMapping("/product/getProductAndUser")
public Object getProductAndUser(long id) {
Map<String,Object> result = new HashMap();
result.put("product",izuUlClientService.getProduct(id));
result.put("user",izuUlClientService.getUsers(id+""));
return result;
}
}
依次啓動eureka,user服務,product服務,zuul服務,customerhystrix服務
在地址欄輸入:
http://localhost/consumer/product/getProductAndUser?id=1
關閉zuul服務
http://localhost/consumer/product/getProductAndUser?id=1
發現服務降級已經開啓
Zuul熔斷
zuul是一個代理服務,但如果被代理的服務突然斷了,這個時候zuul上面會有出錯信息,例如,停止product服務
現在服務的調用方已經做了處理,不會出現這樣的錯誤信息,但一般來說,對於zuul本身代理方,也應該進行zuul的降級處理
修改【microcloud-zuul-gateway】建立fallback回退處理類
package hdk.fallback;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
public class ProviderFallback implements FallbackProvider {
@Override
public String getRoute() {
return "*";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders() ;
headers.set("Content-Type", "text/html; charset=UTF-8");
return headers;
}
@Override
public InputStream getBody() throws IOException {
// 響應體
return new ByteArrayInputStream("產品微服務不可用,請稍後再試。".getBytes());
}
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.BAD_REQUEST;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.BAD_REQUEST.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.BAD_REQUEST.getReasonPhrase();
}
@Override
public void close() {
}
};
}
}
訪問:http://localhost:9501/hdk-api/product-proxy/prodcut/get/1
getRoute:方法可以返回服務的ID,比如‘microcloud-provider-product’,如果需要匹配全部適應 “*”
SpringCloudConfig分佈式配置中心
雖然springcloud使用springboot進行開發,節省了大量的配置文件,但每個服務依然有自己的application.yml配置文件,而且每個服務一般都有負載均衡,所以,這麼依賴對於配置文件的統一管理就非常有必要了
左邊這一塊我們很熟悉,最開始有個eureka,它通過配置文件application.yml啓動,在這個配置文件裏面會指定端口,實例名,註冊地址等
對於服務提供商來說,它也需要把相關信息寫到application.yml文件中,比如數據庫配置,端口,項目名稱等,其中最重要的就就是要指定eureka的具體位置
這是前面反覆說過的,但現在是基於cloudConfig的配置中心,最開始啓動eureka的時候,eureka的具體配置就不是寫死在eureka的application.yml文件中了,這個時候也會有application.yml(bootstrap.yml)配置文件,只是這裏的配置指定的時候config的配置中心,在eureka啓動的時候讀取【配置中心】的配置,並啓動
對於服務提供商也是同樣的道理,以產品服務爲例,它的application.yml文件也不在指定具體的配置,真實需要訪問的數據庫,端口等信息也是在啓動的時候直接從【配置中心】讀取。
所以說config配置中心在其中佔據非常重要的位置,但config裏面的配置從哪來呢?其實是從git服務器裏面來的,開發者需要把相關的配置上傳到git服務器,這裏的git服務器可以自己搭建,也可以直接用github,後面項目爲了方便就直接使用github了。
配置中心搭建
準備好git服務器之後,接下來就要準備配置中心了
【microcloud-config】 新建一個配置中心的服務提供模塊,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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-config</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-security</artifactId>
</dependency>
</dependencies>
</project>
引入springcloudserver的同時,這分佈式配置中心也不是誰都能訪問的,所以增加了安全驗證模塊。
應該還記得這時候的用戶名密碼爲:admin/hdk
【microcloud-config】 新增application.yml配置文件,增加git連接配置信息
server:
port: 7101
spring:
application:
name: microcloud-config
cloud:
config:
server:
git:
uri: https://github.com/huangdongkui/microconfig.git
【microcloud-config】 新增啓動類
package cn.hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class ConfigApp {
public static void main(String[] args) {
SpringApplication.run(ConfigApp.class,args);
}
}
這些工作準備完成後,爲了測試【microcloud-config】是能正確運行的,還需要上傳個配置文件到github
【GITHUB】 上傳一個application.yml
spring:
profiles:
active:
- dev
---
spring:
profiles: dev
application:
name: microconfig-test-dev
---
spring:
profiles: default
application:
name: microconfig-test-default
準備好配置文件後啓動【microcloud-config】
NO | 訪問形式 | 訪問路徑 |
---|---|---|
1 | /{application}-{profile}.yml | http://localhost:7101/application-dev.ymlhttp://localhost:7101/application-default.ymlhttp://localhost:7101/application-beta.yml 不存在 |
2 | /{application}/{profile}[/{label}] | http://localhost:7101/application/dev/masterhttp://localhost:7101/application/default/master |
3 | /{label}/{application}-{profile}.yml | http://localhost:7101/master/application-default.ymlhttp://localhost:7101/master/application-dev.yml |
簡單的客戶端
現在已經成功的搭建好了配置中心,但這個時候如果只通過url的訪問形式其實沒什麼太多的意義,最終還是需要把github相關信息加載到客戶端上進行訪問
新增加一個【microcloud-config-client】模塊,這模塊講讀取github裏面的信息,也不做其他的事情,只是顯示一下。
新建【microcloud-config-client】,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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-config-client</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
【github】上傳一個新的配置文件microcloud-config-client.yml,後面就通過程序來讀取這個配置
```
spring:
profiles:
active:
- dev
---
server:
port: 8201
spring:
profiles: dev
application:
name: microconfig-test-client
eureka:
client:
service-url:
defaultZone: http://admin:hdk@localhost:7001/eureka
---
server:
port: 8102
spring:
profiles: beta
application:
name: microconfig-test-client
eureka:
client:
service-url:
defaultZone: http://admin:hdk@localhost:7001/eureka
【microcloud-config-client】新建bootstrap.yml文件,這文件讀取配置中心的配置
spring:
cloud:
config:
name: microcloud-config-client # 定義要讀取的資源文件的名稱
profile: dev # 定義profile的 名稱
label: master # 定義配置文件所在的分支
uri: http://localhost:7101 # SpringCloudConfig的服務地址
username: admin # 連接的用戶名
password: hdk # 連接的密碼
可能有些人奇怪,爲什麼不直接把相關信息寫道application.yml文件之中,其實這是一種規範
“application.yml”:對應的是用戶級的資源配置項;
“bootstrap.yml”:對應的是系統級的資源配置,其優先級更高
【microcloud-config-client】新建application.yml文件,這文件只是簡單的配置一個應用名稱
spring:
application:
name: microcloud-config-client # 編寫應用的名稱
【microcloud-config-client】新建一個controller,這個controller顯示從服務器下載到的配置文件
package hdk.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigClientController {
@Value("${spring.application.name}")
private String applicationName;
@Value("${eureka.client.serviceUrl.defaultZone}")
private String eurekaServers;
@RequestMapping("/config")
public String getConfig() {
return "ApplicationName = " + this.applicationName + "、EurekaServers = "
+ this.eurekaServers;
}
}
【microcloud-config-client】 新建一個啓動類
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConfigClientApp {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApp.class,args);
}
}
啓動配置中心,訪問,確認配置通過url是能正常訪問的。
http://localhost:7101/microcloud-config-client-beta.yml
啓動【microcloud-config-client】發現tomcat啓動了,佔用的端口就是dev的8201,訪問
http://localhost:8201/config
這個時候簡單的客戶端已經搭建完成。
Eureka與服務提供商讀取配置
有了上面這些基礎,接下來就可以完成這個圖的功能了,這裏依然簡化一下,只考慮product產品服務與eureka
eureka與product服務的配置信息要求去配置中心獲取,所以在正式部署項目之前,先準備兩個配置,上傳到github之中
microcloud-config-eureka-client.yml,這個是eureka的配置文件,這裏就沒有考慮eureka的高可用了
spring:
profiles:
active:
- dev
---
server:
port: 7001
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://admin:hdk@localhost:7001/eureka
instance: # eureak實例定義
hostname: localhost # 定義 Eureka 實例所在的主機名稱
spring:
profiles: dev
security:
user:
name: admin
password: hdk
application:
name: microcloud-config-eureka-client
---
server:
port: 7002
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://admin:hdk@localhost:7002/eureka
instance: # eureak實例定義
hostname: localhost # 定義 Eureka 實例所在的主機名稱
spring:
profiles: beta
security:
user:
name: admin
password: hdk
application:
name: microcloud-config-eureka-client
microcloud-config-product-client.yml,這個事對於產品服務這個服務提供商提供者的配置文件
spring:
profiles:
active:
- dev
---
server:
port: 8080
mybatis:
mapper-locations: # 所有的mapper映射文件
- classpath:mapping/*.xml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 配置當前要使用的數據源的操作類型
driver-class-name: com.mysql.jdbc.Driver # 配置MySQL的驅動程序類
url: jdbc:mysql://localhost:3306/springcloud?serverTimezone=GMT%2B8 # 數據庫連接地址
username: root # 數據庫用戶名
password: root1234% # 數據庫連接密碼
application:
name: microcloud-config-product-client
profiles: dev
logging:
level:
cn.hdk.mapper: debug
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://admin:hdk@localhost:7001/eureka
instance:
instance-id: microcloud-config-product-client
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
info:
app.name: microcloud-provider-product
company.name: hdk
build.artifactId: $project.artifactId$
build.modelVersion: $project.modelVersion$
management:
endpoints:
web:
exposure:
include: '*'
---
server:
port: 8081
mybatis:
mapper-locations: # 所有的mapper映射文件
- classpath:mapping/*.xml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 配置當前要使用的數據源的操作類型
driver-class-name: com.mysql.jdbc.Driver # 配置MySQL的驅動程序類
url: jdbc:mysql://localhost:3306/springcloud?serverTimezone=GMT%2B8 # 數據庫連接地址
username: root # 數據庫用戶名
password: root1234% # 數據庫連接密碼
application:
name: microcloud-config-product-client
profiles: beta
logging:
level:
cn.hdk.mapper: debug
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://admin:hdk@localhost:7002/eureka
instance:
instance-id: microcloud-config-product-client
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
info:
app.name: microcloud-config-product-client
company.name: hdk
build.artifactId: $project.artifactId$
build.modelVersion: $project.modelVersion$
management:
endpoints:
web:
exposure:
include: '*'
有了這兩個配置文件,接下來就可以搭建eureka服務和product服務了
eureka配置
複製【microcloud-eureka】一份,修改成爲【microcloud-config-eureka-client】,
【microcloud-config-eureka-client】 修改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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-config-eureka-client</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-config-eureka-client】創建bootstrap.yml文件,讀取配置中心eureka的配置
spring:
cloud:
config:
uri: http://localhost:7101
name: microcloud-config-eureka-client
profile: beta
label: master
username: admin
password: hdk
【microcloud-config-eureka-client】 修改application.yml,刪除不需要的配置
spring:
application:
name: microcloud-config-eureka-client
由於使用的是beta,它裏面指定的eureka的端口是7002
重啓後訪問:localhost:7002
product服務配置
複製【microcloud-provider-product】項目爲【microcloud-config-product-client】
【microcloud-config-product-client】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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>1.0.0</version>
<artifactId>microcloud-config-product-client</artifactId>
<dependencies>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-security</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-config-product-client】新增bootstrap.yml 文件,配置如下
spring:
cloud:
config:
uri: http://localhost:7101
name: microcloud-config-product-client
profile: beta
label: master
username: admin
password: hdk
【microcloud-config-product-client】 修改application.yml文件
spring:
application:
name: microcloud-config-product-client
啓動product服務,訪問eureka,現在產品服務已經添加上去了。
Config配置中心高可用
現在不管是erueka還是服務提供者都是基於SpringCloudConfig獲取配置文件的,這個時候配置中心就至關重要了,但在真實的項目環境中,難免SpringCloudConfig會出現各種問題,這個時候就需要考慮config的高可用機制了。
其實解決方式也很簡單,把SpringCloudConfig註冊到Eureka就搞定了,這個時候用戶訪問的時候不是直接從配置中心獲取配置,而是通過eureka中獲取配置中心的地址,再從配置中心獲取具體服務的參數就行。
複製【microcloud-eureka】一份,修改成爲【microcloud-ha-config-eureka】,這個eureka不註冊具體的業務服務,只是負責config配置中心的負載均衡使用
【microcloud-ha-config-eureka】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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-ha-config-eureka</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-ha-config-eureka】 修改application.yml文件
server:
port: 7301
eureka:
server:
eviction-interval-timer-in-ms: 1000 #設置清理的間隔時間,而後這個時間使用的是毫秒單位(默認是60秒)
enable-self-preservation: false #設置爲false表示關閉保護模式
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://admin:hdk@localhost:7301/eureka
instance: # eureak實例定義
hostname: localhost # 定義 Eureka 實例所在的主機名稱
spring:
security:
user:
name: admin
password: hdk
application:
name: microcloud-ha-config-eureka
啓動類如下
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class HaConfigEurekaApp {
public static void main(String[] args) {
SpringApplication.run(HaConfigEurekaApp.class,args);
}
}
【microcloud-config】再複製兩份,總共3個配置中心,分別爲【microcloud-config2】【microcloud-config3】
【microcloud-config】【microcloud-config2】【microcloud-config3】 修改pom文件
增加eureka的支持
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
【microcloud-config】【microcloud-config2】【microcloud-config3】修改application.yml文件,增加eureka的註冊地址
server:
port: 7101
spring:
application:
name: microcloud-config
cloud:
config:
server:
git:
uri: https://github.com/hdkeud/microconfig.git
eureka:
client:
service-url:
defaultZone: http://admin:hdk@localhost:7301/eureka
instance:
prefer-ip-address: true # 在地址欄上使用IP地址進行顯示
instance-id: microcloud-config1
啓動eureka並啓動三個配置中心後
【microcloud-config-client】 修改pom文件,增加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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-config-client</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-config-client】 修改bootstrap.yml文件,增加eureka相關配置
spring:
cloud:
config:
name: microcloud-config-client # 定義要讀取的資源文件的名稱
profile: dev # 定義profile的 名稱
label: master # 定義配置文件所在的分支
#uri: http://localhost:7101 # SpringCloudConfig的服務地址
username: admin # 連接的用戶名
password: hdk # 連接的密碼
discovery:
enabled: true # 通過配置中心加載配置文件
service-id: MICROCLOUD-CONFIG # 在eureka之中註冊的服務ID
eureka:
client:
service-url:
defaultZone: http://admin:hdk@localhost:7301/eureka
訪問:http://localhost:8201/config
自動刷新
在整個SpringCloudConfig設計之中,我們已經實現了配置的統一管理,但其實還有一個問題,就是自動刷新。
嘗試修改一下【github】 microcloud-config-client.yml文件
spring:
profiles:
active:
- dev
---
server:
port: 8201
spring:
profiles: dev
application:
name: microconfig-test-client2
eureka:
client:
service-url:
defaultZone: http://admin:hdk@localhost:7001/eureka
---
server:
port: 8102
spring:
profiles: beta
application:
name: microconfig-test-client2
eureka:
client:
service-url:
defaultZone: http://admin:hdk@localhost:7001/eureka
這裏的修改非常簡單,只是修改了下應用名稱,提交後
訪問:http://localhost:8201/config
發現配置並沒有修改,一直要重啓【microcloud-config-client】後纔會發現配置已經修改成功,其實這對大多數應用沒有什麼問題,如果你定時要關注這個小問題也是有辦法處理的,在springcloud裏面可以藉助消息總線SpringCloudBus解決這問題。
springcloudbus是基於SpringCloudStream的,SpringCloudStream的作用其實也是一種適配器模式的體現,消息中間件由很多,比如activemq,rabbitmq ,kafka,不同的消息中間件都會由使用上的差異,而SpringCloudStream就是爲了屏蔽各種消息中間件的差異而存在的.
與之前的架構不一樣的地方在於增加了消息總線,消息總線連接了config配置中心和各個配置中心的消費方,當配置提交到github的時候,可以藉助/bus/refresh刷新,config配置中心再將變更的消息通知到其他的客戶端
【github】 修改配置microcloud-config-client.yml
spring:
profiles:
active:
- dev
---
server:
port: 8201
spring:
profiles: dev
application:
name: microconfig-test-client2
eureka:
client:
serviceUrl:
defaultZone: http://admin:hdk@localhost:7301/eureka
register-with-eureka: false
info:
app.name: microcloud-config-client-dev
company.name: hdk
---
server:
port: 8102
spring:
profiles: beta
application:
name: microconfig-test-client2
eureka:
client:
serviceUrl:
defaultZone: http://admin:hdk@localhost:7301/eureka
register-with-eureka: false
info:
app.name: microcloud-config-client-dev
company.name: hdk
啓動rabbitmq
登陸查看 http://localhost:15672
準備bus配置中心
新建立一個模塊【microcloud-config-bus】,這模塊是配置中心的升級版,作用也是配置中心。
【microcloud-config-bus】 修改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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-config-bus</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-config-bus】 修改application.yml文件,配置上git目錄,一樣連接上eureka,要和消息中間件通訊,所以RabbitMQ的連接信息也配置上
server:
port: 7201
spring:
cloud:
config:
server:
git:
uri: https://github.com/hdkeud/microconfig.git
bus:
trace:
enabled: true
rabbitmq:
host: localhost
port: 5672 # RabbitMQ的監聽端口
username: hdk # 用戶名
password: 5428325 # 密碼
application:
name: microcloud-config-bus
eureka:
client:
serviceUrl:
defaultZone: http://admin:hdk@localhost:7301/eureka
instance:
prefer-ip-address: true # 在地址欄上使用IP地址進行顯示
instance-id: microcloud-config-bus
management:
endpoints:
web:
exposure:
include: "*"
新增啓動類
package hdk;
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 ConfigBusApp {
public static void main(String[] args) {
SpringApplication.run(ConfigBusApp.class,args);
}
}
先啓動eureka,再啓動ConfigBusApp 之後訪問:
發現新的註冊中心已經註冊上去了。
準備新的客戶端
新建立microcloud-config-bus-client模塊,這模塊是註冊中心的客戶端,從註冊中心獲取數據,職責和【microcloud-config-client】一樣,可用基於他拷貝修改,只是增加bus相關的功能。
【microcloud-config-bus-client】 修改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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-config-bus-client</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-config-bus-client】bootstrap.yml 增加rabbitmq相關信息,另外的配置和前面一樣,需要從eureka找到註冊中心,也需要找具體配置文件信息
spring:
cloud:
config:
name: microcloud-config-client # 定義要讀取的資源文件的名稱
profile: dev # 定義profile的 名稱
label: master # 定義配置文件所在的分支
#uri: http://localhost:7101 # SpringCloudConfig的服務地址
username: admin # 連接的用戶名
password: hdk # 連接的密碼
discovery:
enabled: true
service-id: MICROCLOUD-CONFIG-BUS
rabbitmq:
host: localhost
port: 5672 # RabbitMQ的監聽端口
username: hdk # 用戶名
password: 5428325 # 密碼
eureka:
client:
serviceUrl:
defaultZone: http://admin:hdk@localhost:7301/eureka
register-with-eureka: false
修改application.yml文件
spring:
application:
name: microcloud-config-client # 編寫應用的名稱
【microcloud-config-bus-client】 建立一個配置文件的映射類,這類是爲了演示使用,裏面的屬性和github的屬性一一對應,同時增加@RefreshScope,代表這個類是可用基於rabbitmq自動刷新的
package cn.hdk.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@Component
@RefreshScope
public class InfoConfig {
@Value("${info.app.name}")
private String appName ;
@Value("${info.company.name}")
private String companyName ;
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
@Override
public String toString() {
return "InfoConfig{" +
"appName='" + appName + '\'' +
", companyName='" + companyName + '\'' +
'}';
}
}
【microcloud-config-bus-client】修改ConfigClientController
package cn.hdk.controller;
import cn.hdk.config.InfoConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class ConfigClientController {
@Value("${spring.application.name}")
private String applicationName;
@Value("${eureka.client.serviceUrl.defaultZone}")
private String eurekaServers;
@Resource
private InfoConfig infoConfig;
@RequestMapping("/config")
public String getConfig() {
return "ApplicationName = " + this.applicationName + "、EurekaServers = "
+ this.eurekaServers+"、infos = " +infoConfig.toString();
}
}
新增啓動類
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ConfigClientBusApp {
public static void main(String[] args) {
SpringApplication.run(ConfigClientBusApp.class,args);
}
}
啓動後訪問
http://localhost:8201/config,這時候已經能獲得配置中心的數據
測試自動刷新
其實這裏的自動刷新只能說是半自動的。
【github】microcloud-config-client.yml,隨便修改裏面的內容,提交
spring:
profiles:
active:
- dev
---
server:
port: 8201
spring:
profiles: dev
application:
name: microconfig-test-client2
eureka:
client:
serviceUrl:
defaultZone: http://admin:hdk@localhost:7301/eureka
register-with-eureka: false
info:
app.name: microcloud-config-client-dev
company.name: hdk
---
server:
port: 8102
spring:
profiles: beta
application:
name: microconfig-test-client2
eureka:
client:
serviceUrl:
defaultZone: http://admin:hdk@localhost:7301/eureka
register-with-eureka: false
info:
app.name: microcloud-config-client-beta
company.name: hdkbeta
【microcloud-config-bus-client】 刷新客戶端
http://localhost:8201/config
這個時候信息並沒自動刷新,數據還是以前的,這是以爲對應消息中間件來說,還需要給他發個消息,代表數據已經更新了。
【microcloud-config-bus】使用postman發生一條post刷新的指令
http://localhost:7201/actuator/bus-refresh
訪問http://localhost:15672,發現消息隊列裏面已經有消息傳遞了。
【microcloud-config-bus-client】 刷新客戶端
http://localhost:8201/config 發現數據已經跟新
SpringCloudStream 消息驅動
SpringCloudStream看名字就知道他和消息隊列相關,但它又不是消息隊列,準確來說它類似於硬件裏面的驅動程序,也就是前面說的適配器模式的體現
在系統開發裏面難免用到消息隊列,但各個的消息隊列又有所區別,SpringCloudStream的作用就是屏蔽各種消息隊列的區別,對消息隊列的API進行進一步的抽象,使得在springcloud裏面能更加方便的集成各種消息系統
首先來看SpringCloudStream的組成
不管是生產者還是消費者,並不會直接和消息中間件打交道,在springcloudstream中抽象了已成binder(綁定層),有了這一層,使用者並不關心具體的消息中間件配置了,由訪問層真正的和消息隊列進行通信
創建消息生產者
【microcloud-stream-provider】創建一個新的模塊,這模塊負責生產一個消息
【microcloud-stream-provider】 pom文件如下,映入springcloudstream的相關組件
<?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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-stream-provider</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
【microcloud-stream-provider】 修改application.yml文件
server:
port: 8401
spring:
cloud:
stream:
binders: # 在此處配置要綁定的rabbitmq的服務信息;
defaultRabbit: # 表示定義的名稱,用於於binding整合
type: rabbit # 消息組件類型
environment: # 設置rabbitmq的相關的環境配置
spring:
rabbitmq:
addresses: localhost
port: 5672
username: hdk
password: 123456
virtual-host: /
bindings: # 服務的整合處理
output: # 這個名字是一個通道的名稱,在分析具體源代碼的時候會進行說明
destination: hdkExchange # 表示要使用的Exchange名稱定義
content-type: application/json # 設置消息類型,本次爲對象json,如果是文本則設置“text/plain”
binder: defaultRabbit # 設置要綁定的消息服務的具體設置
application:
name: microcloud-stream-provider
【microcloud-stream-provider】 定義一個消息發送接口
package hdk.service;
import cn.hdk.vo.Product;
public interface IMessageProvider {
void send(Product product);
}
【microcloud-stream-provider】 定義接口的實現類
package hdk.service.impl;
import hdk.service.IMessageProvider;
import hdk.vo.Product;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import javax.annotation.Resource;
@EnableBinding(Source.class)
public class MessageProviderImpl implements IMessageProvider{
@Resource
private MessageChannel output; // 消息的發送管道
@Override
public void send(Product product) {
output.send(MessageBuilder.withPayload(product).build());
}
}
【microcloud-stream-provider】 定義啓動類主程序
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StreamProviderApp {
public static void main(String[] args) {
SpringApplication.run(StreamProviderApp.class,args);
}
}
【microcloud-stream-provider】 編寫測試類
package hdk.test;
import hdk.StreamProviderApp;
import hdk.service.IMessageProvider;
import hdk.vo.Product;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@SpringBootTest(classes = StreamProviderApp.class)
@RunWith(SpringRunner.class)
public class TestMessageProvider {
@Resource
private IMessageProvider messageProvider;
@Test
public void testSend() {
Product product = new Product();
product.setProductId(1L);
product.setProductName("messageName");
product.setProductDesc("desc");
messageProvider.send(product);
}
}
運行測試方法
RabbitMq:http://localhost:15672/
創建消息消費者
【microcloud-stream-consumer】 新建模塊
【microcloud-stream-consumer】修改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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-stream-consumer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
<groupId>hdk</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-stream-consumer】 修改application.yml配置文件
server:
port: 8402
spring:
cloud:
stream:
binders: # 在此處配置要綁定的rabbitmq的服務信息;
defaultRabbit: # 表示定義的名稱,用於於binding整合
type: rabbit # 消息組件類型
environment: # 設置rabbitmq的相關的環境配置
spring:
rabbitmq:
addresses: localhost
port: 5672
username: hdk
password: 123456
virtual-host: /
bindings: # 服務的整合處理
input: # 這個名字是一個通道的名稱,在分析具體源代碼的時候會進行說明
destination: hdkExchange # 表示要使用的Exchange名稱定義
content-type: application/json # 設置消息類型,本次爲對象json,如果是文本則設置“text/plain”
binder: defaultRabbit # 設置要綁定的消息服務的具體設置
application:
name: microcloud-stream-consumer
【microcloud-stream-consumer】 定義一個消息的監聽
package hdk.listener;
import hdk.vo.Product;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
@Component
@EnableBinding(Sink.class)
public class MessageListener {
@StreamListener(Sink.INPUT)
public void input(Message<Product> message) {
System.err.println("【*** 消息接收 ***】" + message.getPayload());
}
}
【microcloud-stream-consumer】 創建啓動類
package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StreamConsumerApp {
public static void main(String[] args) {
SpringApplication.run(StreamConsumerApp.class,args);
}
}
啓動後,發現rabbitmq裏面已經有了一個消費者
【microcloud-stream-provider】 運行測試類
【microcloud-stream-consumer】 已經收到消息
【rabbitmq】在消息隊列中,也檢測到了這匿名隊列,可以發現Exchange默認的類型就是TOPIC,RoutingKey我們沒有自定,默認的就是#,會給所有的消費者發消息
自定義消息通道
【micocloud-api】修改pom文件,增加stream的支持
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
</dependencies>
【micocloud-api】 增加管道接口
package hdk.channel;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
public interface DefaultProcess {
public static final String OUTPUT = "hdk_output"; // 輸出通道名稱
public static final String INPUT = "hdk_input"; // 輸入通道名稱
@Input(DefaultProcess.INPUT)
public SubscribableChannel input();
@Output(DefaultProcess.OUTPUT)
public MessageChannel output();
}
【microcloud-stream-provider】 修改application.yml配置文件
server:
port: 8401
spring:
cloud:
stream:
binders: # 在此處配置要綁定的rabbitmq的服務信息;
defaultRabbit: # 表示定義的名稱,用於於binding整合
type: rabbit # 消息組件類型
environment: # 設置rabbitmq的相關的環境配置
spring:
rabbitmq:
addresses: localhost
port: 5672
username: hdk
password: 123456
virtual-host: /
bindings: # 服務的整合處理
hdk_output: # 這個名字是一個通道的名稱,在分析具體源代碼的時候會進行說明
destination: hdkExchange # 表示要使用的Exchange名稱定義
content-type: application/json # 設置消息類型,本次爲對象json,如果是文本則設置“text/plain”
binder: defaultRabbit # 設置要綁定的消息服務的具體設置
application:
name: microcloud-stream-provider
【microcloud-stream-consumer】 修改application.yml文件
server:
port: 8402
spring:
cloud:
stream:
binders: # 在此處配置要綁定的rabbitmq的服務信息;
defaultRabbit: # 表示定義的名稱,用於於binding整合
type: rabbit # 消息組件類型
environment: # 設置rabbitmq的相關的環境配置
spring:
rabbitmq:
addresses: localhost
port: 5672
username: hdk
password: 123456
virtual-host: /
bindings: # 服務的整合處理
hdk_input: # 這個名字是一個通道的名稱,在分析具體源代碼的時候會進行說明
destination: hdkExchange # 表示要使用的Exchange名稱定義
content-type: application/json # 設置消息類型,本次爲對象json,如果是文本則設置“text/plain”
binder: defaultRabbit # 設置要綁定的消息服務的具體設置
application:
name: microcloud-stream-consumer
【microcloud-stream-provider】 修改MessageProviderImpl發送實現類
package hdk.service.impl;
import hdk.channel.DefaultProcess;
import hdk.service.IMessageProvider;
import hdk.vo.Product;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import javax.annotation.Resource;
@EnableBinding(DefaultProcess.class)
public class MessageProviderImpl implements IMessageProvider{
@Resource
@Qualifier("hdk_output")
private MessageChannel output; // 消息的發送管道
@Override
public void send(Product product) {
output.send(MessageBuilder.withPayload(product).build());
}
}
【microcloud-stream-consumer】 修改MessageListener
package hdk.listener;
import hdk.channel.DefaultProcess;
import hdk.vo.Product;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
@Component
@EnableBinding(DefaultProcess.class)
public class MessageListener {
@StreamListener(DefaultProcess.INPUT)
public void input(Message<Product> message) {
System.err.println("【*** 消息接收 ***】" + message.getPayload());
}
}
完成.
分組(隊列)
Group(分組)其實就是對應rabbitmq裏面得隊列,在前面的案例中,我們並沒有指定group,產生的就是一個匿名隊列。
如果啓動了多個【microcloud-stream-consumer】接收者,但並沒有指定group,,那麼將會產生多個匿名的消息隊列,導致多個接收者都會收到同一個消息,也就是說一個消息被重複消費了,這在某些業務場景來說是並不運行的。
這個時候就需要用到group分組了,對於不想重複消費個某消息的各個消費者必須屬於同一個組。
【microcloud-stream-consumer】 修改application.yml
server:
port: 8403
spring:
cloud:
stream:
binders: # 在此處配置要綁定的rabbitmq的服務信息;
defaultRabbit: # 表示定義的名稱,用於於binding整合
type: rabbit # 消息組件類型
environment: # 設置rabbitmq的相關的環境配置
spring:
rabbitmq:
addresses: localhost
port: 5672
username: hdk
password: 123456
virtual-host: /
bindings: # 服務的整合處理
hdk_input: # 這個名字是一個通道的名稱,在分析具體源代碼的時候會進行說明
destination: hdkExchange # 表示要使用的Exchange名稱定義
content-type: application/json # 設置消息類型,本次爲對象json,如果是文本則設置“text/plain”
binder: defaultRabbit # 設置要綁定的消息服務的具體設置
group: hdk_group
application:
name: microcloud-stream-consumer
這個時候服務生產者【microcloud-stream-provider】發送的任何消息都只會被同一個group的某一個消費者處理了。
RoutingKey
RoutingKey其實是RabbitMq的概念,在RabbitMq裏面其實有好幾種Exchange,在SpringCloudStream裏面默認就是使用的最通用的Topic
如果沒有配置RoutingKey,它使用的RoutingKey其實就是#,既類似於fanout的廣播類型
其實也可以使用RoutingKey來實現類似於direct類型,既然直連
【microcloud-stream-consumer】修改application.yml配置文件
server:
port: 8402
spring:
cloud:
stream:
rabbit:
bindings:
hdk_input:
consumer:
bindingRoutingKey: hdkKey # 設置一個RoutingKey信息
binders: # 在此處配置要綁定的rabbitmq的服務信息;
defaultRabbit: # 表示定義的名稱,用於於binding整合
type: rabbit # 消息組件類型
environment: # 設置rabbitmq的相關的環境配置
spring:
rabbitmq:
addresses: localhost
port: 5672
username: hdk
password: 123456
virtual-host: /
bindings: # 服務的整合處理
hdk_input: # 這個名字是一個通道的名稱,在分析具體源代碼的時候會進行說明
destination: hdkExchange # 表示要使用的Exchange名稱定義
content-type: application/json # 設置消息類型,本次爲對象json,如果是文本則設置“text/plain”
binder: defaultRabbit # 設置要綁定的消息服務的具體設置
group: hdk_group
application:
name: microcloud-stream-consumer
【microcloud-stream-provider】定義 RoutingKey 的表達式配置:
server:
port: 8401
spring:
cloud:
stream:
rabbit:
bindings:
hdk_output:
producer:
routingKeyExpression: '''hdkKey'''
binders: # 在此處配置要綁定的rabbitmq的服務信息;
defaultRabbit: # 表示定義的名稱,用於於binding整合
type: rabbit # 消息組件類型
environment: # 設置rabbitmq的相關的環境配置
spring:
rabbitmq:
addresses: localhost
port: 5672
username: hdk
password: 123456
virtual-host: /
bindings: # 服務的整合處理
hdk_output: # 這個名字是一個通道的名稱,在分析具體源代碼的時候會進行說明
destination: hdkExchange # 表示要使用的Exchange名稱定義
content-type: application/json # 設置消息類型,本次爲對象json,如果是文本則設置“text/plain”
binder: defaultRabbit # 設置要綁定的消息服務的具體設置
application:
name: microcloud-stream-provider
SpringCloudSleuth 鏈路跟蹤
在微服務的架構下,系統由大量服務組成,每個服務可能是由不同的團隊開發,開發使用不同的語言,部署在幾千臺服務器上,並且橫跨多個不同的數據中心,一次請求絕大多數情況會涉及多個服務,在系統發生故障的時候,想要快速定位和解決問題,就需要跟蹤服務請求序列
SpringCloudSleuth使用的核心組件是Twitter推出的Zipkin監控組件,zipkin就是一個分佈式的跟蹤系統,用戶收集服務的數據
基本使用
跟蹤服務
【microcloud-sleuth】 新建立模塊,這個模塊用戶跟蹤用戶的請求,把請求的鏈路進行展示
<?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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>hdk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-sleuth</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<version>2.9.3</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>2.9.3</version>
</dependency>
</dependencies>
</project>
【microcloud-sleuth】修改application.yml文件
server:
port: 8601
spring:
application:
name: microcloud-zipkin-server
management:
metrics:
web:
server:
auto-time-requests: false
【microcloud-sleuth】新建啓動類
package .hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin.server.internal.EnableZipkinServer;
@SpringBootApplication
@EnableZipkinServer
public class SleuthApp {
public static void main(String[] args) {
SpringApplication.run(SleuthApp.class,args);
}
}
客戶端配置
爲了演示鏈路追蹤,需要啓動一些列服務
1.【microcloud-eureka】,啓動這個服務的目的是讓product,users兩服務註冊到其中,後面需要zuul的調用
2.修改一下服務的pom文件,增加sleuth的支持
【microcloud-provider-user-hystrix】
【microcloud-provider-product-hystrix】
【microcloud-zuul-gateway】
【microcloud-consumer-hystrix】
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
3.修改一下服務的application.yml文件,增加zipkin的配置
【microcloud-provider-user-hystrix】
【microcloud-provider-product-hystrix】
【microcloud-zuul-gateway】
【microcloud-consumer-hystrix】
spring:
zipkin:
base-url: http://localhost:8601 #所有的數據提交到此服務之中
sender:
type: web #提交的類型是web 服務
sleuth:
sampler:
probability: 1.0 # 定義抽樣比率,默認爲0.1
- 依次啓動
【microcloud-eureka】
【microcloud-provider-user-hystrix】
【microcloud-provider-product-hystrix】
【microcloud-zuul-gateway】
【microcloud-consumer-hystrix】
訪問
http://localhost/consumer/product/getProductAndUser?id=1
訪問跟蹤服務:
http://localhost:8601/zipkin/dependency/
數據持久化
現在以及成功實現了一個 SpringCloudSleuth 的基本操作,但會發現,如果重新啓動【microcloud-sleuth】服務,所有的鏈路跟蹤數據都會丟失,那麼這些數據應該存儲到數據庫裏面的。
但又有另外一個問題,如果請併發量特別大,對於mysql來說可能會承受不了這麼大的併發,爲了解決這個問題,可以使用消息隊列緩衝處理,最後才從mq中把數據存到mysql中
源碼
https://download.csdn.net/download/wolf12/11544808