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>

启动后:

在SpringCloud项目中引入SpringBoot springcloud怎么使用_spring

另外在关闭【microcloud-provider-product】项目后,刷新eureka发现项目还在,隔一段时间后会发现

在SpringCloud项目中引入SpringBoot springcloud怎么使用_maven_02

这其实就是触发了安全模式

【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

在SpringCloud项目中引入SpringBoot springcloud怎么使用_maven_03

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/

在SpringCloud项目中引入SpringBoot springcloud怎么使用_java_04

【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(httpHeaders), List.class).getBody();

可以发现所有的数据调用和转换都是由用户直接来完成的,我们可能不想直接访问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的一个开源项目,他能够在依赖服务失效的情况下,通过隔离系统依赖的方式,防止服务的级联失败(服务的雪崩)

在SpringCloud项目中引入SpringBoot springcloud怎么使用_spring_05

对于服务的熔断机制,其实需要考虑两种情况

  1. 服务提供方存活,但调用接口报错
  2. 服务提供方本身就出问题了

服务提供方报错

其实这种情况类似于异常捕获机制,当出现异常,返回一个通用的接口报文

【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

在SpringCloud项目中引入SpringBoot springcloud怎么使用_数据库_06

【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

在SpringCloud项目中引入SpringBoot springcloud怎么使用_git_07

这个时候对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监控地址

在SpringCloud项目中引入SpringBoot springcloud怎么使用_java_08

这时还会报错。

【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

在SpringCloud项目中引入SpringBoot springcloud怎么使用_git_09

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秒)

在SpringCloud项目中引入SpringBoot springcloud怎么使用_java_10

【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配置文件,而且每个服务一般都有负载均衡,所以,这么依赖对于配置文件的统一管理就非常有必要了

在SpringCloud项目中引入SpringBoot springcloud怎么使用_git_11

左边这一块我们很熟悉,最开始有个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,现在产品服务已经添加上去了。

在SpringCloud项目中引入SpringBoot springcloud怎么使用_数据库_12

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并启动三个配置中心后

在SpringCloud项目中引入SpringBoot springcloud怎么使用_git_13

【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就是为了屏蔽各种消息中间件的差异而存在的.

在SpringCloud项目中引入SpringBoot springcloud怎么使用_maven_14

与之前的架构不一样的地方在于增加了消息总线,消息总线连接了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 之后访问:

http://localhost:7301/

发现新的注册中心已经注册上去了。

在SpringCloud项目中引入SpringBoot springcloud怎么使用_git_15

准备新的客户端

新建立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的组成

在SpringCloud项目中引入SpringBoot springcloud怎么使用_java_16

不管是生产者还是消费者,并不会直接和消息中间件打交道,在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);
    }
}
客户端配置

为了演示链路追踪,需要启动一些列服务

在SpringCloud项目中引入SpringBoot springcloud怎么使用_maven_17

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
  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中

源码