1、SpringColud简介:
Spring Cloud是一系列框架的有序集合。是利用Spring Boot的开发便利性,巧妙地简化了分布式系统基础设施的开发:例如:服务注册、配置中心、消息总线、负载均衡、断路器、数据监控等等,都可以用Spring Boot的开发风格做到一键启动和部署;
SpringCould开发时创建的子项目一般分为两大类:一类是对SpringBoot框架的抽象和封装;第二类是开发了一部分分布式系统的基础设施的实现。
一般情况下都是使用第一类子项目进行开发已经足够使用。【注:SpringColud详细介绍

2、SpringCould开发依赖包引入及依赖包版本管理【pom.xml】:
此处要注意的是SpringCould版本和SpringBoot版本要相互兼容,例如:在此项目中兼容版本分别是springBoot-2.0.4 和 SpringCouldFinchley.SR1是相互兼容的。

<?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>SpringCloud</groupId>
    <artifactId>SpringCloudDemo01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>user-services</module>
        <module>Eureka-service</module>
        <module>consumer-server</module>
    </modules>
    <packaging>pom</packaging>  <!--父级项目pom.xml中的配置-->

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/>
    </parent>
    <!--版本属性配置-->
    <properties>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
        <mapper.version>2.0.3</mapper.version>
        <mysql.version>5.1.46</mysql.version>
        <lombok.version>1.18.6</lombok.version>
    </properties>

    <!--dependencyManagement标签中引入的依赖,子工程还需要手动引入-->
   <dependencyManagement>
        <dependencies>
            <!--springCloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--通用Mapper启动器-->
            <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper-spring-boot-starter</artifactId>
                <version>${mapper.version}</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!--lombok,父类及子类项目中都能使用-->
   <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
    </dependencies>

    <!--springBoot插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.book</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3、SpringCould系项目创建

此处练习使用创建了服务提供者子项目:user-Services、注册中心:Eureka-service服务、服务消费者:consumer-service。

项目结构如下:

springboot requestbady 可空_负载均衡器


3.1、服务提供者:user-services

服务提供者功能:实现与数据库的交互。

3.1.1、服务提供者依赖包【pom.xml】:

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

    <artifactId>user-services</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.0.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
        </dependency>

        <!--注册中心客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
</project>

此处引入了注册客户端的依赖:spring-cloud-starter-netflix-eureka-client,用于向注册中心注册服务,用于消费者调用。
3.1.2、服务提供者配置文件【application.yaml】:

server:
  port: 8088

spring:
  #服务名称
  application:
    name: user-services
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis
    username: root
    password: root

mybatis:
  type-aliases-package: SpringBoot.Starter.Pojo

eureka:
  client:
    service-url:
      #此处如果需要注册到多个Eureka时,以逗号相隔http://127.0.0.1:8888/eureka,http://127.0.0.1:8899/eureka
      defaultZone: http://127.0.0.1:8888/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
    #心跳间隔--服务续约间隔
    lease-renewal-interval-in-seconds: 30
    #服务的失效时间
    lease-expiration-duration-in-seconds: 90

3.1.3、启动入口文件【SpringBootApplicationDemo.java】:

package SpringBoot.Starter;

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

/**
 * @EnableDiscoveryClient : 使用此注解是实现服务注册功能,包含@EnableEurekaClient注解,开启Eureka注册
 */

@EnableDiscoveryClient
@SpringBootApplication
@MapperScan("SpringBoot.Starter.Mapper")
public class SpringBootApplicationDemo {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplicationDemo.class);
    }
}

此文件注解 @EnableDiscoveryClient 就是进行服务注册使用,此注解包含多种注册机制,包含上述Eureka注册服务,当然也可以直接使用Eureka的注解 @EnableEurekaClient

注解 @MapperScan(“SpringBoot.Starter.Mapper”) 是与mybatis中的持久层文件扫描配置一样,扫描指定包下的持久层文件,方便容器进行管理;此注解是依赖包通用Mapper启动器中提供:tk.mybatis mapper-spring-boot-starter ,提供了单表的查询,单表操作不用.xml文件。

3.1.4、持久层文件【UserMapper.java】:

package SpringBoot.Starter.Mapper;

import SpringBoot.Starter.Pojo.UserPojo;
import tk.mybatis.mapper.common.Mapper;

public interface UserMapper extends Mapper<UserPojo> {
}

3.1.5、封装实体类【UserPojo.java】:

package SpringBoot.Starter.Pojo;

import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;

import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import java.util.Date;

@Data
@Table(name = "user")
public class UserPojo {

    /**
     * 此处要注意属性要与表中字段完全一致,并且需要注意的是类型使用封装类型
     */
    @Id
    @KeySql(useGeneratedKeys = true)
    private Integer id;
    private String username;
    private String password;
    private Date birthday;
    private Character sex;
    private String address;
    //备注
    private String content;
    //备注2
    @Transient  //不需要持久化到数据库,该字段不必要在表中存在
    private String content2;
}

3.1.6、Service层实现类【UserService .java】:

package SpringBoot.Starter.Service;

import SpringBoot.Starter.Mapper.UserMapper;
import SpringBoot.Starter.Pojo.UserPojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public UserPojo queryUserInfoById(int id){
        UserPojo user = userMapper.selectByPrimaryKey(id);
        return user;
    }
}

3.1.7、控制器类【ControllerDemo01.java】:

package SpringBoot.Starter.Controller;

import SpringBoot.Starter.Pojo.UserPojo;
import SpringBoot.Starter.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class ControllerDemo01 {
    @Autowired
    private UserService userService;

    @GetMapping("{id2}")
    public UserPojo queryUserInfoController(@PathVariable int id2){
        UserPojo userPojo = userService.queryUserInfoById(id2);
        return userPojo;
    }
}

restdful请求: @GetMapping("{id2}")。

3.2、注册中心服务【Eureka-service】:
注册服务,为Eureka客户端提供注册服务,使用的Eureka依赖包是:spring-cloud-starter-netflix-eureka-server

3.2.1、依赖包配置【pom.xml】:

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

    <dependencies>
        <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-web</artifactId>
            <version>2.0.4.RELEASE</version>
        </dependency>
    </dependencies>
</project>

3.2.2、配置文件【application.yaml】:

server:
  port: 8888

#服务名称
spring:
  application:
    name: eureka-service

#注册中心访问路径配置
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8888/eureka
    #是否注册自己
    #register-with-eureka: false

  ##指定ip,否则联网时获取的ip可能不能正常访问
  instance:
    ip-address: 127.0.0.1
    prefer-ip-address: true

  #服务失效剔除的时间间隔
  server:
    eviction-interval-timer-in-ms: 30000

    #注册机制的自我保护机制,默认是开启状态,默认状态,在一定情况下(例如网络不稳定(会进行自我判断)时)服务失效时也不会马上剔除服务
    #enable-self-preservation: true

此处配置扩展了注册开关(是否注册自己,注册服务默认是会注册自己的)、注册服务的自我保护机制、服务失效剔除时间、指定注册、请求的ip信息。

3.2.3:启动入口文件【SpringCloudEurekaService.java】:

package EurekaService.Application;

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

/**
 * @EnableEurekaServer : Spring Cloud 注册服务注解
 */

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

注解:@EnableEurekaServer 此注解用于注册服务。

3.3、服务消费者【consumer-service】:
主要是获取调用注册服务中已注册成功的服务。

3.3.1、依赖包配置【pom.xml】:

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

    <artifactId>consumer-server</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.0.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--Ribbon负载均衡:需要注意的是引入的一定要是注册中心Eureka的riboon-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-colud-starter-netflix-eureka-ribbon</artifactId>
        </dependency>
    </dependencies>

</project>

服务消费者服务一般会用到负载均衡器,此配置文件中引入了负载均衡器的依赖包Ribbon,

<!--Ribbon负载均衡:需要注意的是引入的一定要是注册中心Eureka的riboon-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-colud-starter-netflix-eureka-ribbon</artifactId>
        </dependency>

3.3.2、配置文件【application.yaml】:

server:
  port: 8080

spring:
  application:
    name: consumer-service

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8888/eureka
    #服务获取时间间隔
    registry-fetch-interval-seconds: 30
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

#使用服务id指定哪个服务使用哪种负载均衡方式 -- 配置默认使用随机数
user-services:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

服务消费者服务一般会用到负载均衡器,此配置文件中可以通过服务提供者ID对负载负载均衡器的默认规则进行制定:

#使用服务id指定哪个服务使用哪种负载均衡方式 -- 配置默认使用随机数
user-services:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

3.3.3、启动入口文件【SpringCloudApplicationDemo01.java】:

package SpringCloudApplication;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableDiscoveryClient
@SpringBootApplication
public class SpringCloudApplicationDemo01 {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudApplicationDemo01.class);
    }

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

在RestTemplate 中使用注解@LoadBalanced,引入了负载均衡器,此处使用注解只是使用负载均衡器的一种方式。

3.3.4、封装类【UserModel.java】:

package SpringCloudApplication.Pojo;

import lombok.Data;

import java.util.Date;

@Data
public class UserModel {

    private Integer id;
    private String username;
    private String password;
    private Date birthday;
    private Character sex;
    private String address;
    //备注
    private String content;

}

3.3.5、控制器类【ControllerDem01.java】:

package SpringCloudApplication.Controller;

import SpringCloudApplication.Pojo.UserModel;
import com.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController //相当于@Controller和@ResponseBody
@RequestMapping("/query")
public class ControllerDem01 {
    @Autowired
    private RestTemplate restTemplate;

    /**
     *
     */
    /*@Autowired
    private DiscoveryClient discoveryClient;*/

    /**
     * 使用ribbon负载均衡器获取服务 -- 默认使用轮询的方式
     *
     * 还有一种负载均衡器的配置使用方式是在RestTemplate创建时使用注解@LoadBalanced -- 默认使用随机的方式实现负载均衡
     */
    /*@Autowired
    private LoadBalancerClient c;*/

    @GetMapping("{id}")
    public UserModel queryUserInfoByRestTemplate(@PathVariable int id){
        //通过服务ID获取实例
        /*List<ServiceInstance> list = discoveryClient.getInstances("user-services");
        //从获取的实例中获取IP和端口
        ServiceInstance serviceInstance = list.get(0);
        String url = serviceInstance.getHost();
        int port = serviceInstance.getPort();
        System.out.println(")))))))))))))))))))))))))))))))))))))"+"http://"+url+":"+port+"/user/"+id);
        UserModel user = restTemplate.getForObject("http://"+url+":"+port+"/user/"+id,UserModel.class);*/
        /**
         * http://xingfu:8088/user/42
         * 注意:使用上述请求地址时一定要断网,否则无法通过本机计算机名访问
         * 所以要在配置文件 application.yaml 中指定ip,配置信息如下:
         * #注册中心访问路径配置
         * eureka:
         *   client:
         *     service-url:
         *       defaultZone: http://127.0.0.1:8888/eureka
         *   ##指定ip,否则联网时获取的ip可能不能正常访问
         *   instance:
         *     ip-address: 127.0.0.1
         *     prefer-ip-address: true
         *
         *
         * 结果:
         * {"id":42,"username":"小二王","password":"123","birthday":"2018-03-02T07:09:37.000+0000","sex":"女","address":"北京金燕龙","content":null}
         */

        /**
         * 负载均衡器获取服务提供者信息
         * 负载均衡的方式:随机、轮询、hashCode、。。。。
         */
        /*ServiceInstance serviceInstance = c.choose("user-services");
        String ip = serviceInstance.getHost();
        int port = serviceInstance.getPort();
        String url = "http://"+ip+":"+port+"/user/"+id;
        System.out.println("----------------------"+url);
        UserModel user = restTemplate.getForObject(url, UserModel.class);*/

        /**
         * 使用注解配置实现负载均衡
         */
        String url = "http://user-services/user/"+id;
        System.out.println("----------------------"+url);
        UserModel user = restTemplate.getForObject(url,UserModel.class);

        /*String url = "http://localhost:8088/user/"+id;
        UserModel user = restTemplate.getForObject(url,UserModel.class);*/
        return user;
    }
}

在此处使用了多两种负载均衡器的使用方法和多种服务调用方式。

注:服务的高可用性启动配置:

springboot requestbady 可空_负载均衡器_02