springCloud入门
Posted G_whang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springCloud入门相关的知识,希望对你有一定的参考价值。
Ribbon是Netflix发布的负载均衡器,它可以帮我们控制HTTP和TCP客户端的行为。只需为Ribbon配置服务提供者地址列表,Ribbon就可基于负载均衡算法计算出要请求的目标服务地址。
Ribbon默认为我们提供了很多的负载均衡算法,例如轮询、随机、响应时间加权等——当然,为Ribbon自定义负载均衡算法也非常容易,只需实现 IRule 接口即可。
在Spring Cloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,选择其中一个服务提供者实例。
负载均衡规则是Ribbon的核心
- AvailabilityFilteringRule:过滤掉一直连接失败的被标记为circuit
tripped的后端Server,并过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个Server的运行状态; - BestAvailableRule:选择一个最小的并发请求的Server,逐个考察Server,如果Server被tripped了,则跳过。
- RandomRule:随机选择一个Server;
- ResponseTimeWeightedRule:作用同WeightedResponseTimeRule,二者作用一样;
RetryRule:对选定的负载均衡策略机上重试机制,在一个配置时间段内当选择Server不成功,则一直尝试使用subRule的方式选择一个可用的server; - RoundRobinRule:轮询选择, 轮询index,选择index对应位置的Server;
- WeightedResponseTimeRule:根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低;
- ZoneAvoidanceRule:复合判断Server所在区域的性能和Server的可用性选择Server
- 如需自定义负载均衡规则,只需实现IRule 接口或继承AbstractLoadBalancerRule、PredicateBasedRule即可
代码如下:
Eureka Server
maven 依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>eurekaServer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eurekaServer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</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>
<!--增加eurekaServer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<!-- 引入spring cloud的依赖,不能少,主要用来管理Spring Cloud生态各组件的版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
// 服务发现
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
配置文件
server:
port: 8761
eureka:
client:
# 是否要注册到其他eureka server 实例
register-with-eureka: false
# 是否从其他eureka server实例获取数据
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka/
服务提供者1
maven
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>test-provider-library</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test-provider-library</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</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-starter-data-jpa</artifactId>
</dependency>
<!-- 引入H2数据库,一种内嵌的数据库,语法类似mysql -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<!-- 引入Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--增加eurekaclient-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<!-- 引入spring cloud的依赖,不能少,主要用来管理Spring Cloud生态各组件的版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
启动类
package com.example.testproviderlibrary;
import com.example.testproviderlibrary.dao.LibraryDao;
import com.example.testproviderlibrary.pojo.LibraryInfo;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import java.util.stream.Stream;
@SpringBootApplication
// 加注解
@EnableEurekaClient
public class TestProviderLibraryApplication {
public static void main(String[] args) {
SpringApplication.run(TestProviderLibraryApplication.class, args);
}
/**
* 使用内置数据库h2 初始化数据
*/
@Bean
ApplicationRunner init (LibraryDao repository){
return args ->{
LibraryInfo libraryInfo1=LibraryInfo.builder().id(1L).name("前门图书馆")
.address("东城区前门东大街").number(1000).count(20).build();
LibraryInfo libraryInfo2=LibraryInfo.builder().id(2L).name("青年路图书馆")
.address("丰台区青年路").number(500).count(10).build();
LibraryInfo libraryInfo3=LibraryInfo.builder().id(2L).name("大地图书馆")
.address("昌平区上地八街").number(800).count(2).build();
Stream.of(libraryInfo1,libraryInfo2,libraryInfo3).forEach(repository :: save);
};
}
}
配置文件
server:
# 指定Tomcat端口
port: 8000
spring:
jpa:
# 让hibernate打印执行的SQL
how-sql: true
## 指定注册到eureka server上的服务名称
application:
name: test-provider-library
logging:
level:
root: INFO
# 配置日志级别,让hibernate打印出执行的SQL参数
org.hibernate: INFO
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
eureka:
client:
service-url:
# 指定eureka server通信地址,注意/eureka/小尾巴不能少
defaultZone: http://localhost:8761/eureka/
instance:
# 是否注册IP到eureka server,如不指定或设为false,那就会注册主机名到eureka server
prefer-ip-address: true
controller
import com.example.testproviderlibrary.pojo.LibraryInfo;
import com.example.testproviderlibrary.service.LibraryService;
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;
import java.util.Optional;
@RestController
@RequestMapping("/library")
public class LibraryController {
@Autowired
private LibraryService libraryService;
@GetMapping("/{id}")
public LibraryInfo findById(@PathVariable Long id){
Optional<LibraryInfo> libraryInfo = this.libraryService.findById(id);
return libraryInfo.get();
}
}
service
import com.example.testproviderlibrary.dao.LibraryDao;
import com.example.testproviderlibrary.pojo.LibraryInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
//可以代替@AutoWired注解,需要注意的是在注入时需要用final定义,或者使用@notnull注解
@RequiredArgsConstructor
public class LibraryService {
private final LibraryDao libraryDao;
public Optional<LibraryInfo> findById(Long id){
return this.libraryDao.findById(id);
}
}
dao
import com.example.testproviderlibrary.pojo.LibraryInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface LibraryDao extends JpaRepository<LibraryInfo,Long> {
}
实体类
import lombok.*;
import javax.persistence.*;
/**
* 图书馆信息
*
*/
@Getter
@Setter
@Builder
@Entity
// 为类提供一个无参的构造方法。
@NoArgsConstructor
// 为类提供一个全参的构造方法
@AllArgsConstructor
public class LibraryInfo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
/**
* 图书馆名称
*/
@Column
private String name;
/**
* 图书馆地址
*/
@Column
private String address;
/**
* 总座位数
*/
@Column
private Integer number;
/**
* 可预约数量
*/
@Column
private Integer count;
}
服务提供者2与服务提供者1代码一致,唯一不同的是端口号,可以直接复制服务提供者1然后改下端口即可
服务消费者
maven引入
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>test-consumer-user-ribbon</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test-consumer-user-ribbon</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</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>
<!-- 引入Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--增加eurekaclient-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<!-- 引入spring cloud的依赖,不能少,主要用来管理Spring Cloud生态各组件的版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class TestConsumerUserRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(TestConsumerUserRibbonApplication.class, args);
}
@Bean
// 只需在 RestTemplate 上添加 LoadBalanced 注解,即可让RestTemplate整合Ribbon!
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
配置文件
server:
port: 8003
spring:
## 指定注册到eureka server上的服务名称
application:
name: test-consumer-user-ribbon
eureka:
client:
service-url:
# 指定eureka server通信地址,注意/eureka/小尾巴不能少
defaultZone: http://localhost:8761/eureka/
instance:
# 是否注册IP到eureka server,如不指定或设为false,那就会注册主机名到eureka server
prefer-ip-address: true
实体类
import lombok.*;
/**
* 图书馆信息
*
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
// 为类提供一个全参的构造方法
@AllArgsConstructor
public class LibraryInfo {
private Long id;
/**
* 图书馆名称
*/
private String name;
/**
* 图书馆地址
*/
private String address;
/**
* 总座位数
*/
private Integer number;
/**
* 可预约数量
*/
private Integer count;
}
controller
import com.example.testconsumeruserribbon.pojo.LibraryInfo;
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;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/library/{id}")
public LibraryInfo findById(@PathVariable Long id){
// 这里用到了RestTemplate的占位符能力
// Ribbon会自动在实际调用时,将目标服务名替换为该服务的IP和端口。
LibraryInfo forObject = restTemplate.getForObject("http://test-provider-library/library/{id}",
LibraryInfo.class, id);
return forObject;
}
}
然后依次启动 注册中心,服务提供者1,服务提供者2,消费者
启动成功后,访问注册中心
http://localhost:8761/
可以看到服务提供者有2个服务
然后访问服务消费者
http://localhost:8003/user/library/1
多刷新几次
然后查看后台服务提供者日志,会发现两个服务都分别打印的有日志,说明负载均衡算法有效
以上是关于springCloud入门的主要内容,如果未能解决你的问题,请参考以下文章
SpringCloud系列四:Eureka 服务发现框架(定义 Eureka 服务端Eureka 服务信息Eureka 发现管理Eureka 安全配置Eureka-HA(高可用) 机制Eur(代码片段
[菜鸟SpringCloud入门]第一章:构建多模块的Maven项目+创建注册中心Eureka子模块