概述
注册中心-Spring Cloud Eureka
Eureka解决了:服务的管理,注册和发现、状态监管、动态路由
Eureka负责管理记录服务提供者的信息。服务调用者无需自己寻找服务,Eureka自动匹配服务给调用者
Eureka与服务之间通过心跳机制进行监控
负载均衡-Spring Cloud Ribbon
Ribbon是Netflix发布的负载均衡器,有助于控制HTTP客户端行为。为Ribbon配置服务提供者地址列表后,Ribbon就可基于负载均衡算法,自动帮助服务消费者请求
Ribbon默认提供的负载均衡算法:轮询、随机、重试法、加权。当然,我们可用自己定义负载均衡算法
熔断器-Spring Cloud Hystrix
Hystrix,英文意思是豪猪,全身是刺,刺是一种保护机制。Hystrix也是Netflix公司的一款组件。
Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库、防止出现级联失败也就是雪崩效应。
预览
环境准备
-- 使用springcloud数据库
USE springcloud;
-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
CREATE TABLE `tb_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) DEFAULT NULL COMMENT '用户名',
`password` varchar(100) DEFAULT NULL COMMENT '密码',
`name` varchar(100) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`sex` int(11) DEFAULT NULL COMMENT '性别,1男,2女',
`birthday` date DEFAULT NULL COMMENT '出生日期',
`created` date DEFAULT NULL COMMENT '创建时间',
`updated` date DEFAULT NULL COMMENT '更新时间',
`note` varchar(1000) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户信息表';
-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES ('1', 'zhangsan', '123456', '张三', '13', '1', '2006-08-01', '2019-05-16', '2019-05-16', '张三');
INSERT INTO `tb_user` VALUES ('2', 'lisi', '123456', '李四', '13', '1', '2006-08-01', '2019-05-16', '2019-05-16', '李四');
springcloud-parent
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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lichun</groupId>
<artifactId>springcloud-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>springcloud-provider</module>
<module>springcloud-provider-demo01</module>
<module>springcloud-consumer</module>
<module>eureka-server</module>
</modules>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<!--SpringCloud包依赖管理-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
eureka-server
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>springcloud-parent</artifactId>
<groupId>com.lichun</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-server</artifactId>
<!--依赖包-->
<dependencies>
<!--eureka-server依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
application.yaml
server:
port: 7001
spring:
application:
name: eureka-server # 应用名称,在Eureka中作为服务的id标识(serviceId)
eureka:
client:
register-with-eureka: false # 是否将自己注册到Eureka中
fetch-registry: false # 是否从eureka中获取服务信息
service-url:
defaultZone: http://localhost:7001/eureka # EurekaServer的地址
server:
# 关闭自我保护模式(默认是打开)
# enable-self-preservation: false
# 对无效的服务进行剔除操作,单位是毫秒
# eviction-interval-timer-in-ms: 5000
EurekaServerApplication.java
package com.lichun;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // 开启Eureka服务
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
springcloud-provider
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>springcloud-parent</artifactId>
<groupId>com.lichun</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-producer</artifactId>
<dependencies>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!--web起步包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MySQL驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--测试包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
application.yaml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/springcloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
application:
# 服务的名字,不同应用的名字不同。如果是集群,名字需要相同
name: springcloud-provider
#指定eureka服务地址
eureka:
client:
service-url:
# EurekaServer的地址
defaultZone: http://localhost:7001/eureka
registry-fetch-interval-seconds: 30
instance:
# 指定IP地址
ip-address: 127.0.0.1
# 访问服务的时候,推荐使用IP
prefer-ip-address: true
# 租约到期,服务时效时间,默认值90秒
# 服务超过90秒没有发生心跳,EurekaServer会将服务从列表移除[前提是EurekaServer关闭了自我保护]
lease-expiration-duration-in-seconds: 90
# 租约续约间隔时间,默认30秒
lease-renewal-interval-in-seconds: 30
server:
port: 18081
ProviderApplication.java
package com.lichun;
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(basePackages = "com.lichun.dao")
// @EnableDiscoveryClient // 开启Eureka客户端发现功能
@EnableEurekaClient // 开启Eureka客户端发现功能,注册中心只能是Eureka
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
User.java
package com.lichun.pojo;
import java.util.Date;
public class User {
private Integer id; // 主键id
private String username; // 用户名
private String password; // 密码
private String name; // 姓名
private Integer age; // 年龄
private Integer sex; // 性别
private Date birthday; // 出生日期
private Date created; // 创建时间
private Date updated; // 更新时间
private String note; // 备注
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
UserDao.java
package com.lichun.dao;
import com.lichun.pojo.User;
import org.apache.ibatis.annotations.Select;
public interface UserDao {
@Select("select * from tb_user where id=#{id}")
public User findById(Integer id);
}
UserService.java
package com.lichun.service;
import com.lichun.pojo.User;
public interface UserService {
public User findById(Integer id);
}
UserServiceImpl.java
package com.lichun.service.impl;
import com.lichun.dao.UserDao;
import com.lichun.pojo.User;
import com.lichun.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User findById(Integer id) {
return userDao.findById(id);
}
}
UserController.java
package com.lichun.controller;
import com.lichun.pojo.User;
import com.lichun.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 UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User findById(@PathVariable(value = "id") Integer id) {
User user = userService.findById(id);
String username = user.getUsername();
user.setUsername(username + " provider");
return user;
}
}
springcloud-provider-demo01
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>springcloud-parent</artifactId>
<groupId>com.lichun</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-producer-demo01</artifactId>
<dependencies>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!--web起步包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MySQL驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--测试包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
application.yaml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/springcloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
application:
# 服务的名字,不同应用的名字不同。如果是集群,名字需要相同
name: springcloud-provider
#指定eureka服务地址
eureka:
client:
service-url:
# EurekaServer的地址
defaultZone: http://localhost:7001/eureka
registry-fetch-interval-seconds: 30
instance:
# 指定IP地址
ip-address: 127.0.0.1
# 访问服务的时候,推荐使用IP
prefer-ip-address: true
# 租约到期,服务时效时间,默认值90秒
# 服务超过90秒没有发生心跳,EurekaServer会将服务从列表移除[前提是EurekaServer关闭了自我保护]
lease-expiration-duration-in-seconds: 90
# 租约续约间隔时间,默认30秒
lease-renewal-interval-in-seconds: 30
server:
port: 18083
ProviderApplication.java
package com.lichun;
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(basePackages = "com.lichun.dao")
// @EnableDiscoveryClient // 开启Eureka客户端发现功能
@EnableEurekaClient // 开启Eureka客户端发现功能,注册中心只能是Eureka
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
User.java
package com.lichun.pojo;
import java.util.Date;
public class User {
private Integer id; // 主键id
private String username; // 用户名
private String password; // 密码
private String name; // 姓名
private Integer age; // 年龄
private Integer sex; // 性别
private Date birthday; // 出生日期
private Date created; // 创建时间
private Date updated; // 更新时间
private String note; // 备注
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
UserDao.java
package com.lichun.dao;
import com.lichun.pojo.User;
import org.apache.ibatis.annotations.Select;
public interface UserDao {
@Select("select * from tb_user where id=#{id}")
public User findById(Integer id);
}
UserService.java
package com.lichun.service;
import com.lichun.pojo.User;
public interface UserService {
public User findById(Integer id);
}
UserServiceImpl.java
package com.lichun.service.impl;
import com.lichun.dao.UserDao;
import com.lichun.pojo.User;
import com.lichun.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User findById(Integer id) {
return userDao.findById(id);
}
}
UserController.java
package com.lichun.controller;
import com.lichun.pojo.User;
import com.lichun.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 UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User findById(@PathVariable(value = "id") Integer id) {
User user = userService.findById(id);
String username = user.getUsername();
user.setUsername(username + " provider-demo01");
return user;
}
}
springcloud-consumer
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>springcloud-parent</artifactId>
<groupId>com.lichun</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-consumer</artifactId>
<!--依赖包-->
<dependencies>
<!--熔断器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 18082
spring:
application:
name: springcloud-consumer
eureka:
client:
service-url:
# EurekaServer的地址
defaultZone: http://localhost:7001/eureka
ConsumerApplication.java
package com.lichun;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
// @EnableDiscoveryClient // 开启Eureka客户端发现功能
@EnableEurekaClient // 开启Eureka客户端发现功能,注册中心只能是Eureka
@EnableCircuitBreaker // 开启熔断
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
// 开启负载均衡
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
User.java
package com.lichun.pojo;
import java.util.Date;
public class User {
private Integer id; // 主键id
private String username; // 用户名
private String password; // 密码
private String name; // 姓名
private Integer age; // 年龄
private Integer sex; // 性别
private Date birthday; // 出生日期
private Date created; // 创建时间
private Date updated; // 更新时间
private String note; // 备注
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
UserController.java
package com.lichun.controller;
import com.lichun.pojo.User;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
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;
import java.util.List;
@RestController
@RequestMapping(value = "/consumer")
// @DefaultProperties(defaultFallback = "defaultFallback")
public class UserController {
@Autowired
private RestTemplate restTemplate;
// 注入该对象,可以用来发现当前注册中心中的服务对象
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping(value = "/{id}")
// 在有可能发生问题的方法上添加降级处理调用
@HystrixCommand(fallbackMethod = "fallBack")
// @HystrixCommand
public User findById(@PathVariable(value = "id") Integer id) {
/*String url = "http://localhost:18081/user/" + id;
return restTemplate.getForObject(url, User.class);*/
/*// 获取指定实例
List<ServiceInstance> instances = discoveryClient.getInstances("SPRINGCLOUD-PROVIDER");
// 获取第一个实例对象
ServiceInstance serviceInstance = instances.get(0);
// 拼接服务地址
String instanceURL = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/user/" + id;
System.out.println(instanceURL);*/
String instanceURL = "http://SPRINGCLOUD-PROVIDER/user/" + id;
return restTemplate.getForObject(instanceURL, User.class);
}
public User fallBack(Integer id) {
User user = new User();
user.setId(id);
user.setUsername("服务降级,默认处理!");
return user;
}
// 创建一个全局默认的兜底的方法 方法 一定不能有参数
public User defaultFallback(){
User user = new User();
user.setId(0);
user.setName("匿名用户全局默认值");
return user;
}
}