springcloud必知功能使用教程

springcloud

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。现在我们一一体验一下这些组件的功能作用。首先从服务提供者和消费者开始。

工程源码:https://download.csdn.net/download/wolf12/11544808

Rest项目演练

  • microcloud-api 模块,作为公共的信息导入配置模块;

  • microcloud-provider-product:作为服务提供者;

  • microcloud-consumer:作为微服务调用的客户端使用;

新建一个maven父项目:microcloud

其中pom文件如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>hdk</groupId>
    <artifactId>springcloud</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>microcloudapi</module>
        <module>microcloudproviderproduct</module>
        <module>microcloudconsumer</module>
    </modules>
    <properties>
        <jdk.version>1.8</jdk.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencyManagement>
    <dependencies>
    <dependency> <!-- 进行SpringCloud依赖包的导入处理 -->
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Finchley.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    <dependency> <!-- SpringCloud离不开SpringBoot,所以必须要配置此依赖包 -->
    <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.1.2.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.31</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>
        <dependency>
            <groupId>hdk</groupId>
            <artifactId>microcloud-api</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>
    </dependencyManagement>
    <build>
        <finalName>microcloud</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${jdk.version}</source><!-- 源代码使用的开发版本 -->
                    <target>${jdk.version}</target><!-- 需要生成的目标class文件的编译版本 -->
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

microcloud-api

【microcloud-api】模块,建立一个公共模板,这模块的主要功能是提供公共处理的工具类,实体,接口等。

pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>hdk</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>microcloud-api</artifactId>
    <version>1.0.0</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

由于实体对象不管是服务提供放还是消费者都需要用到,实体对象先创建到api模块中,创建一个Product实体
package hdk.vo;
import java.io.Serializable;
public class Product implements Serializable {

    private Long productId;
    private String productName;
    private String productDesc;

    public String getProductDesc() {
        return productDesc;
    }
    public void setProductDesc(String productDesc) {
        this.productDesc = productDesc;
    }
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    public Long getProductId() {
        return productId;
    }
    public void setProductId(Long productId) {
        this.productId = productId;
    }
    @Override
    public String toString() {
        return "Product{" +
                "productId=" + productId +
                ", productName='" + productName + '\'' +
                ", productDesc='" + productDesc + '\'' +
                '}';
    }
}

由于实体对象不管是服务提供放还是消费者都需要用到,实体对象先创建到api模块中,创建一个Product实体

package cn.hdk.vo;
import java.io.Serializable;
public class Product implements Serializable {

    private Long productId;
    private String productName;
    private String productDesc;

    public String getProductDesc() {
        return productDesc;
    }
    public void setProductDesc(String productDesc) {
        this.productDesc = productDesc;
    }
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    public Long getProductId() {
        return productId;
    }
    public void setProductId(Long productId) {
        this.productId = productId;
    }
    @Override
    public String toString() {
        return "Product{" +
                "productId=" + productId +
                ", productName='" + productName + '\'' +
                ", productDesc='" + productDesc + '\'' +
                '}';
    }
}

服务提供方

创建一个Product Rest提供者的项目模块,这个模块对应的数据库脚本如下

CREATE DATABASE springcloud CHARACTER SET UTF8 ;
USE springcloud ;
CREATE TABLE product (
prodcutId BIGINT AUTO_INCREMENT ,
productName VARCHAR(50) ,
 productDesc VARCHAR(50) ,
CONSTRAINT pk_prodcut_id PRIMARY KEY(prodcutId)
) ;

INSERT INTO product(productName,productDesc) VALUES ('电子锁骨',database()) ;
INSERT INTO product(productName,productDesc) VALUES ('Springboot',database()) ;
INSERT INTO product(productName,productDesc) VALUES ('水表',database()) ;
INSERT INTO product(productName,productDesc) VALUES ('门禁',database()) ;
INSERT INTO product(productName,productDesc) VALUES ('摄像头',database()) ;

【microcloud-provider-product】模块继续使用mybaits对数据库进行操作,pom文件如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>hdk</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <version>1.0.0</version>

    <artifactId>microcloud-provider-product</artifactId>
    <dependencies>
        <dependency>
            <groupId>hdk</groupId>
            <artifactId>microcloud-api</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

</project>

【microcloud-provider-product】创建一个ProductMapper对数据库的操作接口,这个接口方法特别简单

package hdk.mapper;
import hdk.vo.Product;
import java.util.List;
public interface ProductMapper {
    boolean create(Product product);
    public Product findById(Long id);
    public List<Product> findAll();
}

【microcloud-provider-product】新增修改application.yml文件,追加对mybatis以及数据库的支持

server:
 port: 8080
mybatis:
 mapper-locations: # 所有的mapper映射文件
 - classpath:mapping/*.xml
spring:
 datasource:
   type: com.alibaba.druid.pool.DruidDataSource # 配置当前要使用的数据源的操作类型
   driver-class-name: com.mysql.cj.jdbc.Driver # 配置MySQL的驱动程序类
   url: jdbc:mysql://localhost:3306/springcloud?serverTimezone=GMT%2B8 # 数据库连接地址
   username: root # 数据库用户名
   password: 111111% # 数据库连接密码
logging:
  level:
hdk.mapper: debug

【microcloud-provider-product】创建修改src/main/resources/mapping/ProductMapper.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="hdk.mapper.ProductMapper">
    <select id="findById" resultType="cn.hdk.vo.Product" parameterType="long">
        select productId,productName,productDesc from product WHERE productId=#{id} ;
    </select>
    <select id="findAll" resultType="cn.hdk.vo.Product">
        SELECT productId,productName,productDesc from product;
    </select>
    <insert id="create" parameterType="cn.hdk.vo.Product">
        INSERT INTO product(productName,productDesc) VALUES (#{productName},database()) ;
    </insert>
</mapper>

【microcloud-provider-product】建立IProductService接口,并创建相关实现类

package hdk.service;
import hdk.vo.Product;
import java.util.List;
public interface IProductService {
    Product get(long id);
    boolean add(Product product);
    List<Product> list();
}


package hdk.service.impl;

import hdk.mapper.ProductMapper;
import hdk.service.IProductService;
import hdk.vo.Product;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;

@Service
public class ProductServiceImpl implements IProductService {

    @Resource
    private ProductMapper productMapper;

    @Override
    public Product get(long id) {
        return productMapper.findById(id);
    }

    @Override
    public boolean add(Product product) {
        return productMapper.create(product);
    }

    @Override
    public List<Product> list() {
        return productMapper.findAll();
    }
}

【microcloud-provider-product】 定义主程序类,并定义好mapper扫描包

package hdk;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("hdk.mapper")
public class ProductApp{
    public static void main(String[] args) {
        SpringApplication.run(ProductApp.class,args);
    }
}

【microcloud-provider-product】编写单元测试

package hdk;
import hdk.service.IProductService;
import hdk.vo.Product;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@SpringBootTest(classes = ProductApp.class)
@RunWith(SpringRunner.class)
public class ProductServiceTest {
    @Resource
    private IProductService iProductService;
    @Test
    public void testGet() {
        System.out.println(iProductService.get(1));
    }
    @Test
    public void testAdd() {
        Product dept = new Product() ;
        dept.setProductName("lison-" + System.currentTimeMillis());
        System.out.println(iProductService.add(dept));
    }
    @Test
    public void testList() {
        System.out.println(iProductService.list());
    }
}

【microcloud-provider-product】建立ProductController建立一个Rest服务类

package hdk.controller;
import hdk.service.IProductService;
import hdk.vo.Product;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
@RestController
@RequestMapping("/prodcut")
public class ProductController {

    @Resource
    private IProductService iProductService;

    @RequestMapping(value="/get/{id}")
    public Object get(@PathVariable("id") long id) {
        return this.iProductService.get(id) ;
    }
    @RequestMapping(value="/add")
    public Object add(@RequestBody Product product) {
        return this.iProductService.add(product) ;
    }
    @RequestMapping(value="/list")
    public Object list() {
        return this.iProductService.list() ;
    }
}

浏览器访问:

调用get请求:localhost:8080/product/get/1

调用list请求:localhost:8080/product/list

服务消费方

创建一个maven新模块:【microcloud-consumer】这个模块作为服务的消费方,调用前面的product服务

【microcloud-consumer】修改pom文件,pom文件内容如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>hdk</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>microcloud-consumer</artifactId>
    <dependencies>
        <dependency>
            <groupId>hdk</groupId>
            <artifactId>microcloud-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

</project>

【microcloud-consumer】修改application.yml配置文件

server:

port: 80

【microcloud-consumer】创建Rest配置类,在这需要调用Rest服务,一般需要用到RestTemplate类对象

package hdk.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestConfig {
    @Bean
    public RestTemplate restTemplate() {
        return  new RestTemplate();
    }
}

【microcloud-consumer】新建一个controller,负责使用RestTemplate调用远程的product服务

package hdk.controller;

import hdk.vo.Product;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {
    public static final String PRODUCT_GET_URL = "http://localhost:8080/prodcut/get/";
    public static final String PRODUCT_LIST_URL="http://localhost:8080/prodcut/list/";
    public static final String PRODUCT_ADD_URL = "http://localhost:8080/prodcut/add/";
    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/product/get")
    public Object getProduct(long id) {
        Product product = restTemplate.getForObject(PRODUCT_GET_URL + id, Product.class);
        return  product;
    }

    @RequestMapping("/product/list")
    public  Object listProduct() {
        List<Product> list = restTemplate.getForObject(PRODUCT_LIST_URL, List.class);
        return  list;
    }

    @RequestMapping("/product/add")
    public Object addPorduct(Product product) {
        Boolean result = restTemplate.postForObject(PRODUCT_ADD_URL, product, Boolean.class);
        return  result;
    }
}

【microcloud-consumer】编写启动类

package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

调用测试

新增:http://localhost/consumer/product/add?productName=lison

列表查询:http://localhost/consumer/product/list

获得单个数据:http://localhost/consumer/product/get?id=1

SpringSecurity

前面使用了RestTemplate进行远程接口调用,但要注意,这些Rest服务最终都可能暴露在公网的,任何人都可能调用,如果你的Rest服务属于一些私密信息,这样会导致信息的泄露。

如果想进行安全方面的处理,首先要在服务的提供方上进行处理。

【microcloud-provider-product】修改pom文件,追加 SpringSecurity 相关依赖信息

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
</dependency>

【microcloud-provider-product】修改application.yml配置文件,进行安全的用户名配置

spring: 
 security:
   user:
     name: admin  # 认证用户名
     password: hdk  # 认证密码
     roles:
      - USER # 授权角色

在项目中访问rest接口,localhost:8080/product/list,这个时候会要求先输入用户名以及密码才能允许访问

服务消费方处理

【microcloud-consumer】 修改RestConfig配置类,在里面添加 HttpHeaders 的配置信息

package cn.hdk.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.Base64;

@Configuration
public class RestConfig {

    @Bean
    public RestTemplate restTemplate() {
        return  new RestTemplate();
    }

    @Bean
    public HttpHeaders getHeaders() { // 要进行一个Http头信息配置
        HttpHeaders headers = new HttpHeaders(); // 定义一个HTTP的头信息
        String auth = "admin:hdk"; // 认证的原始信息
        byte[] encodedAuth = Base64.getEncoder()
                .encode(auth.getBytes(Charset.forName("US-ASCII"))); // 进行一个加密的处理
        String authHeader = "Basic " + new String(encodedAuth);
        headers.set("Authorization", authHeader);
        return headers;
    }
}

【microcloud-consumer】 修改ConsumerProductController,在进行服务端调用的时候加上这个头信息

package hdk.controller;


import hdk.vo.Product;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {
    public static final String PRODUCT_GET_URL = "http://localhost:8080/prodcut/get/";
    public static final String PRODUCT_LIST_URL="http://localhost:8080/prodcut/list/";
    public static final String PRODUCT_ADD_URL = "http://localhost:8080/prodcut/add/";

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private HttpHeaders httpHeaders;

    @RequestMapping("/product/get")
    public Object getProduct(long id) {
        Product product = restTemplate.exchange(PRODUCT_GET_URL + id,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), Product.class).getBody();
        return  product;
    }

    @RequestMapping("/product/list")
    public  Object listProduct() {
        List<Product> list = restTemplate.exchange(PRODUCT_LIST_URL,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), List.class).getBody();
        return  list;
    }

    @RequestMapping("/product/add")
    public Object addPorduct(Product product) {
        Boolean result = restTemplate.exchange(PRODUCT_ADD_URL, HttpMethod.POST,new HttpEntity<Object>(product,httpHeaders), Boolean.class).getBody();
        return  result;
    }
}

调用测试

新增:http://localhost/consumer/product/add?productName=lison

列表查询:http://localhost/consumer/product/list

获得单个数据:http://localhost/consumer/product/get?id=1

microcloud-security模块

现在服务提供方只有一个Product服务,但真实的项目开发中必然有多个服务提供方,绝大多数情况下,这些服务都会用到安全验证,而且密码也会一样,如果每个服务都单独维护,每次密码变动改动都会很大,所以应该单独建立一个安全验证的模块

创建一个microcloud-security模块,修改其pom文件如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>hdk</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <version>1.0.0</version>

    <artifactId>microcloud-security</artifactId>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

</project>

【springcloud】修改父工程pom文件,把相应的版本依赖加到里面

<dependency>
            <groupId>hdk</groupId>
            <artifactId>microcloud-api</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>hdk</groupId>
            <artifactId>microcloud-security</artifactId>
            <version>1.0.0</version>
        </dependency>

【microcloud-security】建立一个统一的安全配置类,这个类负责用户以及密码相关的配置

package hdk.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(AuthenticationManagerBuilder auth)
            throws Exception {
                auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("root").password(new BCryptPasswordEncoder().encode("hdk")).roles("USER").
                        and().withUser("admin").password(new BCryptPasswordEncoder().encode("hdk")).roles("USER", "ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {


        http.httpBasic().and().authorizeRequests().anyRequest()
                .fullyAuthenticated();
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

}

【microcloud-provider-product】修改pom文件,删除spring-boot-starter-security的依赖信息,并加入自己定义的microcloud-security依赖

 <!--<dependency>-->
            <!--<groupId>org.springframework.boot</groupId>-->
            <!--<artifactId>spring-boot-starter-security</artifactId>-->
        <!--</dependency>-->
        <dependency>
            <groupId>hdk</groupId>
            <artifactId>microcloud-security</artifactId>
        </dependency>

【microcloud-provider-product】修改application.yml,删除与安全相关的配置项。

# security:
#   user:
#     roles:
#      - USER # 授权角色
#     name:  root
#     password:  hdk

调用测试

新增:http://localhost/consumer/product/add?productName=lison

列表查询:http://localhost/consumer/product/list

获得单个数据:http://localhost/consumer/product/get?id=1

Eureka服务注册与发现

Eureka 服务端

新建一个microcloud-eureka模块,这模块做的事情非常简单,既启动Eureka的服务端,pom文件如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>hdk</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>microcloud-eureka</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

</project>

【microcloud-eureka】修改application.yml文件,在里面配置eureka相关信息

server:
 port: 7001
eureka:
  instance: # eureak实例定义
    hostname: localhost # 定义 Eureka 实例所在的主机名称

【microcloud-eureka】新增Eureka启动类,增加Eureka服务端注解

package hdk;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaApp {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApp.class,args);
    }
}

在浏览器上执行

http://localhost:7001/

服务提供方注册到Eureka

【microcloud-provider-product】修改pom文件,增加eureka客户端相关信息

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

【microcloud-provider-product】修改application.yml配置文件,在者个文件中定义要注册的eureka服务的地址

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
      

【microcloud-provider-product】修改启动类,在这个类上增加eureka客户端的注解信息

package hdk;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@MapperScan("cn.hdk.mapper")
@EnableEurekaClient
public class ProductApp{
    public static void main(String[] args) {
        SpringApplication.run(ProductApp.class,args);
    }
}

启动后发现Application的名字是UNKNOWN,为此应该为这单独取一个名字
【microcloud-provider-product】修改application.yml配置文件,为这个微服务起一个名字

spring:
 application:
   name: microcloud-provider-product

【microcloud-provider-product】修改application.yml配置文件,追加主机名称的显示:

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    instance-id: microcloud-provider-product
    

【microcloud-provider-product】修改application.yml配置文件

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    instance-id: microcloud-provider-product
    prefer-ip-address: true #显示IP
    

【microcloud-provider-product】如果想看状态信息需要增加actuator模块,这一块的内容已经在讲springboot的时候讲过,修改pom文件,增加

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        

【microcloud-provider-product】修改application.yml文件,追加info相关配置

info:
  app.name: microcloud-provider-product
  company.name: hdk
  build.artifactId: $project.artifactId$
  build.modelVersion: $project.modelVersion$

注意:由于在yml文件中使用了$,这个时候启动是会报错的,因此还需要一个maven-resources-plugin插件的支持

【microcloud】在父工程增加插件,修改pom文件

<build>
        <finalName>microcloud</finalName>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <delimiters>
                        <delimiter>$</delimiter>
                    </delimiters>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${jdk.version}</source><!-- 源代码使用的开发版本 -->
                    <target>${jdk.version}</target><!-- 需要生成的目标class文件的编译版本 -->
                </configuration>
            </plugin>
        </plugins>
    </build>

启动后:

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

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

【microcloud-eureka】设置服务的清理间隔时间,修改application.yml文件

server:
 port: 7001
eureka:
  server:
    eviction-interval-timer-in-ms: 1000   #设置清理的间隔时间,而后这个时间使用的是毫秒单位(默认是60秒)
    enable-self-preservation: false #设置为false表示关闭保护模式
  client:
    fetch-registry: false
    register-with-eureka: false
  instance: # eureak实例定义
    hostname: localhost # 定义 Eureka 实例所在的主机名称

【microcloud-provider-product】修改application.yml配置

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    instance-id: microcloud-provider-product
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5  # 如果现在超过了5秒的间隔(默认是90秒)

由于所有的服务都注册到了 Eureka 之中

这样如果配置了“lease-expiration-duration-in-seconds”此选项,

表示距离上一次发送心跳之后等待下一次发送心跳的间隔时间,如果超过了此间隔时间,则认为该微服务已经宕机了。

【microcloud-provider-product】对于注册到 Eureka 上的服务,可以通过发现服务来获取一些服务信息,修改ProductController,增加一个方法

package hdk.controller;


import cn.hdk.service.IProductService;
import cn.hdk.vo.Product;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;

@RestController
@RequestMapping("/prodcut")
public class ProductController {

    @Resource
    private IProductService iProductService;

    @Resource
    private DiscoveryClient client ; // 进行Eureka的发现服务

    @RequestMapping(value="/get/{id}")
    public Object get(@PathVariable("id") long id) {
        return this.iProductService.get(id) ;
    }
    @RequestMapping(value="/add")
    public Object add(@RequestBody Product product) {
        return this.iProductService.add(product) ;
    }
    @RequestMapping(value="/list")
    public Object list() {
        return this.iProductService.list() ;
    }


    @RequestMapping("/discover")
    public Object discover() { // 直接返回发现服务信息
        return this.client ;
    }
}

【microcloud-provider-product】修改ProductApp, 在主程序中启用发现服务项

package hdk;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@MapperScan("cn.hdk.mapper")
@EnableEurekaClient
@EnableDiscoveryClient
public class ProductApp{
    public static void main(String[] args) {
        SpringApplication.run(ProductApp.class,args);
    }
}

访问:localhost:8080/prodcut/discover

Eureka 安全机制

一般情况下Eureka 和服务的提供注册者都会在一个内网环境中,但免不了在某些项目中需要让其他外网的服务注册到Eureka,这个时候就有必要让Eureka增加一套安全认证机制了,让所有服务提供者通过安全认证后才能注册进来

【microcloud-eureka】修改pom文件,引入SpringSecurity的依赖包

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

【microcloud-eureka】 修改application.yml文件,增加用户、密码验证

server:
 port: 7001
eureka:
  server:
    eviction-interval-timer-in-ms: 1000   #设置清理的间隔时间,而后这个时间使用的是毫秒单位(默认是60秒)
    enable-self-preservation: false #设置为false表示关闭保护模式
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
        defaultZone: http://admin:hdk@localhost:7001/eureka
  instance: # eureak实例定义
    hostname: localhost # 定义 Eureka 实例所在的主机名称

spring:
  security:
    user:
      name: admin
      password: hdk

【microcloud-provider-product】修改application.yml文件,增加验证信息

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://admin:hdk@localhost:7001/eureka
  instance:
    instance-id: microcloud-provider-product
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5  # 如果现在超过了5秒的间隔(默认是90秒)

【microcloud-eureka】新增配置类EurekaSecurityConfig,重写configure方法,把csrf劫持关闭

package hdk;


import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class EurekaSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        super.configure(http);
    }
}

HA 高可用

现在的Eureka还是单节点的情况,如果Eureka出现了错误,将会导致整个集群无法继续使用,这个时候就需要考虑Eureka的高可用了。

现在需要3个eureka ,每个eureka都需要配置hostname,所有先修改hosts文件内容如下

127.0.0.1 eureka1

127.0.0.1 eureka2

127.0.0.1 eureka3

【microcloud-eureka】为了方便操作,讲microcloud-eureka项目复制两份,分别复制为【microcloud-eureka2】、 【microcloud-eureka2】

【microcloud-eureka】修改application.yml配置文件,修改端口以及注册位置

server:
 port: 7001
eureka:
  server:
    eviction-interval-timer-in-ms: 1000   #设置清理的间隔时间,而后这个时间使用的是毫秒单位(默认是60秒)
    enable-self-preservation: false #设置为false表示关闭保护模式
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
        #defaultZone: http://admin:hdk@localhost:7001/eureka
        defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
  instance: # eureak实例定义
    hostname: eureka1 # 定义 Eureka 实例所在的主机名称

spring:
  security:
    user:
      name: admin
      password: hdk

【microcloud-eureka2】修改application.yml配置文件

server:
 port: 7002
eureka:
  server:
    eviction-interval-timer-in-ms: 1000   #设置清理的间隔时间,而后这个时间使用的是毫秒单位(默认是60秒)
    enable-self-preservation: false #设置为false表示关闭保护模式
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
        #defaultZone: http://admin:hdk@localhost:7001/eureka
        defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
  instance: # eureak实例定义
    hostname: eureka2 # 定义 Eureka 实例所在的主机名称

spring:
  security:
    user:
      name: admin
      password: hdk

【microcloud-eureka3】修改application.yml配置文件

server:
 port: 7003
eureka:
  server:
    eviction-interval-timer-in-ms: 1000   #设置清理的间隔时间,而后这个时间使用的是毫秒单位(默认是60秒)
    enable-self-preservation: false #设置为false表示关闭保护模式
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
        #defaultZone: http://admin:hdk@localhost:7001/eureka
        defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
  instance: # eureak实例定义
    hostname: eureka3 # 定义 Eureka 实例所在的主机名称

spring:
  security:
    user:
      name: admin
      password: hdk

启动eureka,eureka2,eureka3,进入服务的后台查看副本

登陆http://localhost:7001/

【microcloud-provider-product】修改application.yml配置文件,配置多台enreka的注册

server:
 port: 8080
mybatis:
 mapper-locations: # 所有的mapper映射文件
 - classpath:mapping/*.xml
spring:
 datasource:
   type: com.alibaba.druid.pool.DruidDataSource # 配置当前要使用的数据源的操作类型
   driver-class-name: com.mysql.cj.jdbc.Driver # 配置MySQL的驱动程序类
   url: jdbc:mysql://localhost:3306/springcloud?serverTimezone=GMT%2B8 # 数据库连接地址
   username: root # 数据库用户名
   password: root1234% # 数据库连接密码
 application:
   name: microcloud-provider-product
# security:
#   user:
#     roles:
#      - USER # 授权角色
#     name:  root
#     password:  hdk

logging:
  level:
    cn.hdk.mapper: debug

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      #defaultZone: http://admin:hdk@localhost:7001/eureka
      defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
  instance:
    instance-id: microcloud-provider-product
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5  # 如果现在超过了5秒的间隔(默认是90秒)

info:
  app.name: microcloud-provider-product
  company.name: hdk
  build.artifactId: $project.artifactId$
  build.modelVersion: $project.modelVersion$

打包发布

在项目中,需要讲Eureka发布到具体服务器上进行执行,打包部署其实和springboot里面讲的大同小异和properties文件稍微有点不同,对于properties文件,不同的环境会有不同的配置文件比如application-dev.properties,application-test.properties,application-pro.properties等
但如果是yml文件,所有的的配置都再同一个yml文件中

【microcloud-eureka】修改application.yml文件

spring:
  profiles:
    active:
      - dev-7001

---
server:
 port: 7001
eureka:
  server:
    eviction-interval-timer-in-ms: 1000   #设置清理的间隔时间,而后这个时间使用的是毫秒单位(默认是60秒)
    enable-self-preservation: false #设置为false表示关闭保护模式
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
        defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
  instance: # eureak实例定义
    hostname: eureka1 # 定义 Eureka 实例所在的主机名称
spring:
  profiles: dev-7001
  security:
    user:
      name: admin
      password: hdk
  application:
    name: microcloud-eureka

---
server:
 port: 7002
eureka:
  server:
    eviction-interval-timer-in-ms: 1000   #设置清理的间隔时间,而后这个时间使用的是毫秒单位(默认是60秒)
    enable-self-preservation: false #设置为false表示关闭保护模式
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
        defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
  instance: # eureak实例定义
    hostname: eureka2 # 定义 Eureka 实例所在的主机名称
spring:
  profiles: dev-7002
  security:
    user:
      name: admin
      password: hdk
  application:
    name: microcloud-eureka2

---
server:
 port: 7003
eureka:
  server:
    eviction-interval-timer-in-ms: 1000   #设置清理的间隔时间,而后这个时间使用的是毫秒单位(默认是60秒)
    enable-self-preservation: false #设置为false表示关闭保护模式
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
        defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
  instance: # eureak实例定义
    hostname: eureka3 # 定义 Eureka 实例所在的主机名称
spring:
  profiles: dev-7003
  security:
    user:
      name: admin
      password: hdk
  application:
    name: microcloud-eureka3

【microcloud-eureka】添加一个打包插件,修改pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>hdk</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>microcloud-eureka</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>

    <build>
        <finalName>eureka-server</finalName>
        <plugins>
            <plugin> <!-- 该插件的主要功能是进行项目的打包发布处理 -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration> <!-- 设置程序执行的主类 -->
                    <mainClass>cn.hdk.EurekaApp</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

【microcloud-eureka】 在pom文件所在目录

mvn clean install package

接下来就可以在项目的编译目录发现

eureka-server.jar 文件

采用默认的方式执行 eureka-server.jar那么此时将运行在 7001 端口上:java -jar eureka-server.jar

运行其它的两个 profile 配置:

· 运行“dev-7002”profile:java -jar eureka-server.jar --spring.profiles.active=dev-7002;

· 运行“dev-7003”profile:java -jar eureka-server.jar --spring.profiles.active=dev-7003

Ribbon负载均衡

现在服务提供方已经可以通过Eureka进行注册了,但对于服务的消费者,目前并没有处理,对于服务的消费方,也应该连接上eureka,进行服务的获取,这个时候就应该使用Ribbon这个组件了

ribbon对应的pom文件如下

<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

Ribbon基本使用

【microcloud-consumer】 修改pom文件,增加eureka的支持

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>hdk</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>microcloud-consumer</artifactId>
    <dependencies>
        <dependency>
            <groupId>hdk</groupId>
            <artifactId>microcloud-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
</project>

【microcloud-consumer】 修改RestConfig配置类,在获取RestTemplate对象的时候加入Ribbon的配置信息

package cn.hdk.config;


import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.Base64;

@Configuration
public class RestConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return  new RestTemplate();
    }

    @Bean
    public HttpHeaders getHeaders() { // 要进行一个Http头信息配置
        HttpHeaders headers = new HttpHeaders(); // 定义一个HTTP的头信息
        String auth = "root:hdk"; // 认证的原始信息
        byte[] encodedAuth = Base64.getEncoder()
                .encode(auth.getBytes(Charset.forName("US-ASCII"))); // 进行一个加密的处理
        String authHeader = "Basic " + new String(encodedAuth);
        headers.set("Authorization", authHeader);
        return headers;
    }

}

【microcloud-consumer】 修改RestConfig配置类,在获取RestTemplate对象的时候加入Ribbon的配置信息```

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
        defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka

【microcloud-consumer】修改项目启动类,增加Eureka客户端的配置注解

package hdk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

【microcloud-consumer】 修改ConsumerProductController控制器

现在在eureka中注册的服务名称都是大写字母:

MICROCLOUD-PROVIDER-PRODUCT

package hdk.controller;


import hdk.vo.Product;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {

    public static final String PRODUCT_GET_URL = "http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/get/";
    public static final String PRODUCT_LIST_URL="http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/list/";
    public static final String PRODUCT_ADD_URL = "http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/add/";

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private HttpHeaders httpHeaders;

    @RequestMapping("/product/get")
    public Object getProduct(long id) {
        Product product = restTemplate.exchange(PRODUCT_GET_URL + id,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), Product.class).getBody();
        return  product;
    }

    @RequestMapping("/product/list")
    public  Object listProduct() {
        List<Product> list = restTemplate.exchange(PRODUCT_LIST_URL,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), List.class).getBody();
        return  list;
    }

    @RequestMapping("/product/add")
    public Object addPorduct(Product product) {
        Boolean result = restTemplate.exchange(PRODUCT_ADD_URL, HttpMethod.POST,new HttpEntity<Object>(product,httpHeaders), Boolean.class).getBody();
        return  result;
    }


}

访问地址:http://localhost/consumer/product/list

这个时候Ribbon与Eureka已经整合成功

Ribbon负载均衡的实现

通过上面的代码发现我们用到了一个注解@LoadBalanced,根据这名字大概就能知道Ribbon是可以实现负载均衡的

【microcloud-provider-product】 复制两份

分别为【microcloud-provider-product2】与【microcloud-provider-product3】

【springcloud数据库】复制两份

分别为【springcloud2数据库】【springcloud3数据库】 里面分别执行spingcloud数据库的脚本

【microcloud-provider-product2】修改application.yml文件如下

server:
 port: 8081
mybatis:
 mapper-locations: # 所有的mapper映射文件
 - classpath:mapping/*.xml
spring:
 datasource:
   type: com.alibaba.druid.pool.DruidDataSource # 配置当前要使用的数据源的操作类型
   driver-class-name: com.mysql.cj.jdbc.Driver # 配置MySQL的驱动程序类
   url: jdbc:mysql://localhost:3306/springcloud2?serverTimezone=GMT%2B8 # 数据库连接地址
   username: root # 数据库用户名
   password: root1234% # 数据库连接密码
 application:
   name: microcloud-provider-product
# security:
#   user:
#     roles:
#      - USER # 授权角色
#     name:  root
#     password:  hdk

logging:
  level:
    hdk.mapper: debug

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      #defaultZone: http://admin:hdk@localhost:7001/eureka
      defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
  instance:
    instance-id: microcloud-provider-product2
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5  # 如果现在超过了5秒的间隔(默认是90秒)



info:
  app.name: microcloud-provider-product2
  company.name: hdk
  build.artifactId: $project.artifactId$
  build.modelVersion: $project.modelVersion$

【microcloud-provider-product3】修改application.yml文件如下

server:
 port: 8082
mybatis:
 mapper-locations: # 所有的mapper映射文件
 - classpath:mapping/*.xml
spring:
 datasource:
   type: com.alibaba.druid.pool.DruidDataSource # 配置当前要使用的数据源的操作类型
   driver-class-name: com.mysql.cj.jdbc.Driver # 配置MySQL的驱动程序类
   url: jdbc:mysql://localhost:3306/springcloud3?serverTimezone=GMT%2B8 # 数据库连接地址
   username: root # 数据库用户名
   password: root1234% # 数据库连接密码
 application:
   name: microcloud-provider-product
# security:
#   user:
#     roles:
#      - USER # 授权角色
#     name:  root
#     password:  hdk

logging:
  level:
    cn.hdk.mapper: debug

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      #defaultZone: http://admin:hdk@localhost:7001/eureka
      defaultZone: http://admin:hdk@eureka1:7001/eureka,http://admin:hdk@eureka2:7002/eureka,http://admin:hdk@eureka3:7003/eureka
  instance:
    instance-id: microcloud-provider-product3
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5  # 如果现在超过了5秒的间隔(默认是90秒)



info:
  app.name: microcloud-provider-product3
  company.name: hdk
  build.artifactId: $project.artifactId$
  build.modelVersion: $project.modelVersion$

分别启动3个服务提供方,访问

http://localhost:8080/product/get/1

http://localhost:8081/product/get/1

http://localhost:8082/product/get/1

确认3个服务是能正确提供访问的

【microcloud-consumer】启动
访问:http://localhost/consumer/product/list

自定义Ribbon路由

前面已经使用Ribbon实现了路由,通过测试,也不难发现默认Ribbon使用的路由策略是轮询,可以看下源代码BaseLoadBalancer

全局路由配置

这种负载均衡的策略其实也是可以由用户来修改的,如果想要去修改,可以使用自定义的LoadBalance

【microcloud-consumer】 修改RestConfig

package hdk.config;


import com.netflix.loadbalancer.IRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.Base64;

@Configuration
public class RestConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return  new RestTemplate();
    }

    @Bean
    public HttpHeaders getHeaders() { // 要进行一个Http头信息配置
        HttpHeaders headers = new HttpHeaders(); // 定义一个HTTP的头信息
        String auth = "root:hdk"; // 认证的原始信息
        byte[] encodedAuth = Base64.getEncoder()
                .encode(auth.getBytes(Charset.forName("US-ASCII"))); // 进行一个加密的处理
        String authHeader = "Basic " + new String(encodedAuth);
        headers.set("Authorization", authHeader);
        return headers;
    }

    @Bean
    public IRule ribbonRule() { // 其中IRule就是所有规则的标准
        return new com.netflix.loadbalancer.RandomRule(); // 随机的访问策略
    }

}

这个时候重启测试发现,默认的路由规则已经变成了随机

单独设置某个Ribbon的路由

有时候,某个消费者可能需要访问多个多个服务提供方,而希望每个服务提供方提供的路由规则并不相同,这个时候就不能让Spring扫描到IRULE,需要通过@RibbonClient 来指定服务于配置的关系
【microcloud-consumer】 修改RestConfig,删除IRULE

package cn.hdk.config;


import com.netflix.loadbalancer.IRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.Base64;

@Configuration
public class RestConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return  new RestTemplate();
    }

    @Bean
    public HttpHeaders getHeaders() { // 要进行一个Http头信息配置
        HttpHeaders headers = new HttpHeaders(); // 定义一个HTTP的头信息
        String auth = "root:hdk"; // 认证的原始信息
        byte[] encodedAuth = Base64.getEncoder()
                .encode(auth.getBytes(Charset.forName("US-ASCII"))); // 进行一个加密的处理
        String authHeader = "Basic " + new String(encodedAuth);
        headers.set("Authorization", authHeader);
        return headers;
    }

//    @Bean
//    public IRule ribbonRule() { // 其中IRule就是所有规则的标准
//        return new com.netflix.loadbalancer.RandomRule(); // 随机的访问策略
//    }

}

【microcloud-consumer】新增一个路由规则的配置类,注意这个类不应该放到SpringCloud扫描不到的位置,否则又回变成全局的IRULE,所以这个时候应该单独使用一个新的包,着个包和启动并不在同一个包下

package hdk.config;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;

public class RibbonConfig {
    @Bean
    public IRule ribbonRule() { // 其中IRule就是所有规则的标准
        return new com.netflix.loadbalancer.RandomRule(); // 随机的访问策略
    }
}

【microcloud-consumer】 修改启动类,使用@RibbonClient指定配置类

package hdk;
import hdkconfig.RibbonConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.RibbonClients;

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name ="MICROCLOUD-PROVIDER-PRODUCT" ,configuration = RibbonConfig.class)
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

这里的name 只服务的名称,如果需要有多个服务提供方,这个时候可以使用@RibbonClients进行配置

服务提供方的信息获取

在服务的消费方,也是可以获取到服务提供方的具体信息

【microcloud-consumer】修改ConsumerProductController

package cn.hdk.controller;


import cn.hdk.vo.Product;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {

    public static final String PRODUCT_GET_URL = "http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/get/";
    public static final String PRODUCT_LIST_URL="http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/list/";
    public static final String PRODUCT_ADD_URL = "http://MICROCLOUD-PROVIDER-PRODUCT/prodcut/add/";

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private HttpHeaders httpHeaders;

    @Resource
    private LoadBalancerClient loadBalancerClient;

    @RequestMapping("/product/get")
    public Object getProduct(long id) {
        Product product = restTemplate.exchange(PRODUCT_GET_URL + id,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), Product.class).getBody();
        return  product;
    }

    @RequestMapping("/product/list")
    public  Object listProduct() {
        ServiceInstance serviceInstance = this.loadBalancerClient.choose("MICROCLOUD-PROVIDER-PRODUCT") ;
        System.out.println(
                "【*** ServiceInstance ***】host = " + serviceInstance.getHost()
                        + "、port = " + serviceInstance.getPort()
                        + "、serviceId = " + serviceInstance.getServiceId());
        List<Product> list = restTemplate.exchange(PRODUCT_LIST_URL,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), List.class).getBody();
        return  list;
    }

    @RequestMapping("/product/add")
    public Object addPorduct(Product product) {
        Boolean result = restTemplate.exchange(PRODUCT_ADD_URL, HttpMethod.POST,new HttpEntity<Object>(product,httpHeaders), Boolean.class).getBody();
        return  result;
    }

}

脱离Eureka使用Ribbon

之前所用Ribbon都是从Eureka中获取服务并通过@LoadBalanced来实现负载均衡的,其实Ribbon也可以脱离Eureka来使用

复制【microcloud-consumer】 成一个新的模块【microcloud-consumer-ribbon】

【microcloud-consumer-ribbon】 修改pom文件,删除eureka的依赖添加ribbon的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>hdk</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>microcloud-consumer-ribbon</artifactId>
    <dependencies>
        <dependency>
            <groupId>hdk</groupId>
            <artifactId>microcloud-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <!--<dependency>-->
            <!--<groupId>org.springframework.cloud</groupId>-->
            <!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
        <!--</dependency>-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
    </dependencies>

</project>

【microcloud-consumer-ribbon】 修改application.yml配置文件

server:
 port: 80

ribbon:
eureka:
 enabled: false

MICROCLOUD-PROVIDER-PRODUCT:
ribbon:
  listOfServers: http://localhost:8080,http://localhost:8081,http://localhost:8082

【microcloud-consumer-ribbon】 修改 RestConfig,删除@LoadBalanced注解

package hdk.config;


import com.netflix.loadbalancer.IRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.Base64;

@Configuration
public class RestConfig {

    @Bean
    //@LoadBalanced
    public RestTemplate restTemplate() {
        return  new RestTemplate();
    }

    @Bean
    public HttpHeaders getHeaders() { // 要进行一个Http头信息配置
        HttpHeaders headers = new HttpHeaders(); // 定义一个HTTP的头信息
        String auth = "root:hdk"; // 认证的原始信息
        byte[] encodedAuth = Base64.getEncoder()
                .encode(auth.getBytes(Charset.forName("US-ASCII"))); // 进行一个加密的处理
        String authHeader = "Basic " + new String(encodedAuth);
        headers.set("Authorization", authHeader);
        return headers;
    }


}

【microcloud-consumer-ribbon】修改ConsumerProductController,修改服务的调用URI

package hdk.controller;


import cn.hdk.vo.Product;
import cn.xiangxue.config.RibbonConfig;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.net.URI;
import java.util.List;

@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {

    public static final String PRODUCT_TOPIC = "MICROCLOUD-PROVIDER-PRODUCT";

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private HttpHeaders httpHeaders;

    @Resource
    private LoadBalancerClient loadBalancerClient;


    @RequestMapping("/product/list")
    public  Object listProduct() {
        ServiceInstance serviceInstance = this.loadBalancerClient.choose(PRODUCT_TOPIC) ;
        System.out.println(
                "【*** ServiceInstance ***】host = " + serviceInstance.getHost()
                        + "、port = " + serviceInstance.getPort()
                        + "、serviceId = " + serviceInstance.getServiceId());

        URI uri = URI.create(String.format("http://%s:%s/prodcut/list/" ,
                serviceInstance.getHost(), serviceInstance.getPort()));

        List<Product> list = restTemplate.exchange(uri,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), List.class).getBody();
        return  list;
    }
}

​ 【microcloud-consumer-ribbon】启动

访问:http://localhost/consumer/product/list

Feign接口服务

前面已经学习了Ribbon,从Eureka获取服务的实例在通过RestTemplate调用,并转换成需要的对象

List list = restTemplate.exchange(PRODUCT_LIST_URL,HttpMethod.GET,new HttpEntity

posted on 2019-08-13 16:06  wolf12  阅读(1047)  评论(0编辑  收藏  举报