SpringCloud
登山不以艰险而止,则必臻乎峻岭矣
1. 微服务
1.1 定义
微服务是一种高内聚,低耦合架构风格,James Lewis,Martin Fowler
1.2 解决方案
序号 | 名称 | API | 通信 | 服务注册与发现 | 熔断机制 |
---|---|---|---|---|---|
1 | Cloud NetFlix 一站式解决方案 | zuul组件 | 基于Httpclient —Http通信方式:同步、阻塞 | Eureka | Hystrix |
2 | Apache Dubbo Zookeeper半自动,需要整合别人的 | 无,需要自己实现 | Dubbo | Zookeeper | 无,借助Hystrix |
3 | Spring Cloud Alibaba 一站式解决方案,更简单 | Zuul 和 Gateway组件 | Dubbo | Nacos | Sentinel |
1.3 优缺点
序号 | 优点 | 缺点 |
---|---|---|
1 | 松耦合 | 开发人员要处理分布式系统的复杂性 |
2 | 单一职责原则 | 多服务运维难度,随着服务的增加,运维的压力也在增大 |
3 | 易于和第三方集成 | 服务间通信成本 |
4 | 易于修改和维护等 | 数据一致性等 |
1.4 技术栈
微服务条目 | 技术 |
---|---|
服务开发 | springboot, spring, springmvc |
服务配置与管理 | Netflix公司的Archaius, 阿里的Diamond等 |
服务注册与发现 | Eureka, Consul, Zookeeper等 |
服务调用 | Rest, RPC, gRPC |
服务熔断器 | Hystrix, Envoy等 |
负载均衡 | Ribbon, Nginx等 |
服务接口调用(客户端调用服务的简化工具) | Feign等 |
消息队列 | Kafka, RabbitMQ, ActiveMQ等 |
服务配置中心管理 | SpringCloudConfig, cher等 |
服务路由(API网关) | zuul等 |
服务监控 | Zabbix, Nagios, Metrice, Specatator等 |
全链路追踪 | Zipkin, Brave, Dapper等 |
服务部署 | Docker, OpenStack, Kubernetes等 |
数据流操作开发包 | SpringCloud Stream(封装与Redis, Rabbit, KafKa等发送接收消息) |
事务消息总线 | SpringClound Bus |
1.5 微服务架构
-
阿里:dubbo+HFS
-
京东:JSF
-
新浪:Motan
-
当当网: DubboX
功能点/服务框架 | Netflix/SpringCloud | Motan | gRPC | Thrift | Dubbo/DubboX |
---|---|---|---|---|---|
功能定位 | 完整的微服务框架 | RPC框架,但整合了ZK或Consul,实现集群环境的基本服务注册发现 | RPC框架 | RPC框架 | 服务框架 |
支持Rest | 是,Ribbon支持多种可拔插的序列号选择 | 否 | 否 | 否 | 否 |
支持RPC | 否 | 是(Hession2) | 是 | 是 | 是 |
支持多语言 | 是(Rest形式) | 否 | 是 | 是 | 否 |
负载均衡 | 是(服务端zuul+客户端Ribbon),zuul-服务,动态路由,云端负载均衡Eureka(针对中间层服务器) | 是(客户端) | 否 | 否 | 是(客户端) |
配置服务 | Netfix Archaius,Spring Cloud Config Server 集中配置 | 是(Zookeeper提供) | 否 | 否 | 否 |
服务调用链监控 | 是(zuul),zuul提供边缘服务,API网关 | 否 | 否 | 否 | 否 |
高可用/容错 | 是(服务端Hystrix+客户端Ribbon) | 是(客户端) | 否 | 否 | 是(客户端) |
典型应用案例 | Netflix | Sina | |||
社区活跃程度 | 高 | 一般 | 高 | 一般 | 2017年后重新开始维护,之前中断了5年 |
学习难度 | 中等 | 低 | 高 | 高 | 低 |
文档丰富程度 | 高 | 一般 | 一般 | 一般 | 高 |
其他 | Spring Cloud Bus为我们的应用程序带来了更多管理端点 | 支持降级 | Netflix内部在开发集成gRPC | IDL定义 | 实践的公司比较多 |
2. SpringCloud
2.1 定义
SpringCloud,基于SpringBoot提供了-套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件。
springcloud学习1
springcloud中文API文档
SpringCloud中国社区
SpringCloud中文网
2.2 Dubbo 和 SpringCloud对比
最大区别:Spring Cloud 抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式
名称/服务 | Dubbo | SpringCloud |
---|---|---|
服务注册中心 | Zookeeper | Spring Cloud Netfilx Eureka |
服务调用方式 | RPC | REST API |
服务监控 | Dubbo-monitor | Spring Boot Admin |
断路器 | 不完善 | Spring Cloud Netfilx Hystrix |
服务网关 | 无 | Spring Cloud Netfilx Zuul |
分布式配置 | 无 | Spring Cloud Config |
服务跟踪 | 无 | Spring Cloud Sleuth |
消息总栈 | 无 | Spring Cloud Bus |
数据流 | 无 | Spring Cloud Stream |
批量任务 | 无 | Spring Cloud Task |
2.3 版本
spring-boot-starter-parent | spring-cloud-dependencles | ||
---|---|---|---|
版本号 | 发布日期 | 版本号 | 发布日期 |
2.0.2.RELEASE | 2018-05 | Fomchiey.BULD-SNAPSHOT | 2018-x |
2.0.6.RELEASE | 2018-10 | Fomchiey-SR2 | 2018-10 |
2.1.4.RELEASE | 2019-04 | Greenwich.SR1 | 2019-03 |
3. SpringCloud开发
3.1 导入依赖
<?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.xxy</groupId>
<artifactId>springcloud</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>springcloud-api</module>
<module>springcloud-server-provider</module>
<module>springcloud-user-consumer</module>
</modules>
<packaging>pom</packaging>
<properties>
<spring-cloud-dependencies.version>Greenwich.SR1</spring-cloud-dependencies.version>
<spring-boot-dependencies.version>2.1.4.RELEASE</spring-boot-dependencies.version>
<mysql-connector-java.version>8.0.22</mysql-connector-java.version>
<druid-spring-boot-starter.version>1.2.8</druid-spring-boot-starter.version>
<mybatis-spring-boot-starter.version>2.1.1</mybatis-spring-boot-starter.version>
<lombok.version>1.18.22</lombok.version>
<junit.version>4.13.1</junit.version>
<logback-core.version>1.2.3</logback-core.version>
<slf4j-api.version>1.7.36</slf4j-api.version>
</properties>
<dependencyManagement>
<dependencies>
<!--springcloud依赖-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--SpringBoot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version>
</dependency>
<!--日志测试-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback-core.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-api.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3.2 进行新建springboot项目或者maven项目
- springcloud-api
- springcloud-provider
- springcloud-consumer
3.3 springcloud-api编写
- 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</artifactId>
<groupId>com.xxy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-api</artifactId>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
- User.java
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class User implements Serializable {
private Long id;
private String name;
private String version;
}
3.4 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</artifactId>
<groupId>com.xxy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-server-provider</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.xxy</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
- application.yml
server:
port: 8081
mybatis:
type-aliases-package: com.xxy.cloud.pojo
onfig-location: [classpath:mybatis-config.xml]
mapper-locations: [classpath:mapper/*.xml]
spring:
application:
name: springcloud-provider
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/temp1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
username: root
password: 'root'
druid:
db-type: com.alibaba.druid-spring-boot-starter
max-active: 20
- UserMapper.java
@Mapper
@Repository
public interface UserMapper {
int insertUser(User user);
int deleteUserById(Long id);
int updateUser(User user);
User selectUserById(Long id);
List<User> selectUserByAll();
}
- UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxy.springcloud.mapper.UserMapper">
<select id="selectUserByAll" resultType="User">
select id,name from user
</select>
<select id="selectUserById" resultType="User" parameterType="Long">
select id,name from user where id = #{id}
</select>
<insert id="insertUser" parameterType="User">
insert into user(id,name) values(#{id},#{name})
</insert>
<delete id="deleteUserById" parameterType="Long">
delete from user where id = #{id}
</delete>
<update id="updateUser" parameterType="User">
update user set name=#{name} where id = #{id}
</update>
</mapper>
- UserService.java
package com.xxy.springcloud.service;
import com.xxy.cloud.pojo.User;
import java.util.List;
/**
* @author xxy
* @version 1.0
* @date 2023-02-11-4:11
*/
public interface UserService {
/**
* 查询所有用户
* @return List<User>
*/
List<User> selectUserByAll();
/**
* 通过id查询用户
* @param id id
* @return User
*/
User selectUserById(Long id);
/**
* 插入用户
* @param user 用户
* @return int
*/
int insertUser(User user);
/**
* 删除用户
* @param id 用户id
* @return int
*/
int deleteUserById(Long id);
/**
* 更新用户
* @param user 用户
* @return int
*/
int updateUser(User user);
}
- UserServiceImpl.java
package com.xxy.springcloud.service;
import com.xxy.cloud.pojo.User;
import com.xxy.springcloud.mapper.UserMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* @author xxy
* @version 1.0
* @date 2023-02-11-4:11
*/
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
public List<User> selectUserByAll() {
return userMapper.selectUserByAll();
}
public User selectUserById(Long id) {
return userMapper.selectUserById(id);
}
public int insertUser(User user) {
return userMapper.insertUser(user);
}
public int deleteUserById(Long id) {
return userMapper.deleteUserById(id);
}
public int updateUser(User user) {
return userMapper.updateUser(user);
}
}
- UserController.java
package com.xxy.springcloud.controller;
import com.xxy.cloud.pojo.User;
import com.xxy.springcloud.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* @author xxy
* @version 1.0
* @date 2023-03-11-23:15
*/
@RestController
@RequestMapping(value = "/user")
public class UserController {
@Resource
private UserService userService;
@RequestMapping(value = "/insert/{id}",method = RequestMethod.GET)
public String insertUser(@PathVariable("id") Long id,@RequestBody User user) {
user.setId(id).setName("li");
int i = userService.insertUser(user);
if (i > 0) {
return "增加成功"+i;
}
return "增加失败"+i;
}
@RequestMapping( value = "/del/{id}",method = RequestMethod.GET)
public String deleteUser(@PathVariable("id") Long id) {
int i = userService.deleteUserById(id);
if (i > 0) {
return "删除成功"+i;
}
return "删除失败" + i;
}
@RequestMapping( value = "/update/{id}",method = RequestMethod.GET)
public String updateUser(@PathVariable("id") Long id,User user) {
user.setId(id).setName("lisi");
int i = userService.updateUser(user);
if (i > 0) {
return "修改成功"+i;
}
return "修改失败" + i;
}
@RequestMapping(value = "/select",method = RequestMethod.GET)
public List<User> selectUserByAll() {
List<User> users = userService.selectUserByAll();
if (users.size() == 0) {
return null;
}
return users;
}
@RequestMapping(value = "/select/{id}",method = RequestMethod.GET)
public User seleteUserById(@PathVariable("id") Long id) {
// log.info("信息id"+id);
User user = userService.selectUserById(id);
if (user == null) {
return null;
}
return user;
}
}
- 启动类UserProvider_8081
package com.xxy.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author xxy
* @version 1.0
* @date 2023-03-19-20:42
*/
@SpringBootApplication
public class UserProvider_8081 {
public static void main(String[] args) {
SpringApplication.run(UserProvider_8081.class,args);
}
}
3.5 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</artifactId>
<groupId>com.xxy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-user-consumer</artifactId>
<dependencies>
<dependency>
<groupId>com.xxy</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
- application.yml
server:
port: 80
- config.java
package com.xxy.springcloud.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author xxy
* @version 1.0
* @date 2023-03-19-21:51
*/
@Configuration
public class ConfigBean {
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
- UserConsumerController.java
package com.xxy.springcloud.controller;
import com.xxy.cloud.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author xxy
* @version 1.0
* @date 2023-03-19-21:48
*/
@RestController
@RequestMapping("/consumer")
public class UserConsumerController {
public static final String REST_URL_PREFIX = "http://localhost:8081/user";
@Resource
private RestTemplate restTemplate;
@RequestMapping(value = "/insert/{id}")
public boolean insertUser(@PathVariable("id") Long id,User user) {
return restTemplate.getForObject(REST_URL_PREFIX + "/insert/" + id,boolean.class);
}
@RequestMapping(value = "/select/{id}",method = RequestMethod.GET)
public User seleteUserById(@PathVariable("id") Long id) {
return restTemplate.getForObject(REST_URL_PREFIX + "/select/" + id,User.class);
}
@RequestMapping(value = "/select",method = RequestMethod.GET)
public List<User> selectUserByAll() {
return restTemplate.getForObject(REST_URL_PREFIX+"/select",List.class);
}
}
- 启动类UserConsumer_80.java
package com.xxy.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author xxy
* @version 1.0
* @date 2023-03-19-22:19
*/
@SpringBootApplication
public class UserConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(UserConsumer_80.class,args);
}
}
- 输入
localhost/consumer/select/100
测试
4. Eureka服务注册与发现
此已经过时,了解思想即可,nacos
4.1 简述
- 定义
Eureka是Netflix的一个子模块,遵循AP原则,实现服务注册和发现,Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper
- 基本架构
- Eureka Server:提供服务注册与发现。和zookeeper客户端一样
- Service Provider:将自身服务注册到Eureka中,从而使消费方能够找到
- Service Consumer:服务消费方从Eureka中获取注册服务列表,从而找到消费服务
4.2 开发
- 导入依赖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</artifactId>
<groupId>com.xxy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-eureka</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>3.0.4</version>
</dependency>
</dependencies>
</project>
- 配置application.yml
server:
port: 7001
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,我的职责就是维护服务实例,并不需要去搜索服务
service-url:
#设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- 启动类EurekaServer_7001.java
package com.xxy.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author xxy
* @version 1.0
* @date 2023-03-20-0:38
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
- 输入
localhost:7001
进行测试
4.3 注册和发现提供者端
-
导入依赖
-
进行配置
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
instance:
#修改Eureka中status的默认描述信息。不配置默认为DESKTOP-XXX描述
instance-id: springcloud-server-provider
- 启动类增加@EnableEurekaClient
@SpringBootApplication
@EnableEurekaClient
public class UserProvider_8081 {
public static void main(String[] args) {
SpringApplication.run(UserProvider_8081.class,args);
}
}
- 输入
localhost:7001
进行测试
4.4 自我保护机制
某时刻某一个微服务不可以用了 , eureka不会立刻清理,依旧会对该微服务的信息进行保存!
-
默认情况下,如果EurekaServer在一定时间内没有接收到某 个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。 但是当网络分区故障发生时,微服务与Eureka之间无法正常通行,以上行为可能变得非常危险了---- 因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过 自我保护机制来解决这个问题–当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障) , 那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务) .当网络故障恢复后,该EurekaServer节 点会自动退出自我保护模式。
-
自我保护模式是-种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮和稳定
-
在SpringCloud中, 可以使用 eureka. server. enable-self-preservation = false 禁用自我保护模式[不推荐关闭自我保护机制]
4.5 Eureka集群环境配置
对应的 Eureka Server服务的状态是UP,
则不会向另外两个节点(eureka7002,eureka7003)发送请求,
相应地页面上也就没有显示。一旦停止 eureka7001 服务注册中心,则 user-8001 服务会向 eureka7002 发送注册请求。
- 导入依赖
- 进行配置
server:
port: 7001
#Eureka配置
eureka:
instance:
hostname: eureka7001.com #Eureaka服务端的实例名称
client:
register-with-eureka: false #表示是否向Eureka注册中心注册自己
fetch-registry: false #如果fetch-registry为false,则表示自己为注册中心
service-url: #监控页面
#单机:点进去参考源码,可看到默认的url端口配置为8761,我们设置为自己的端口。
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
#集群(除自身外 关联其他所有)
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
- 分别配置启动类
4.6 Eureka和Zookeeper
Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。
- 简述
- RDBMS (Mysql. Oracle. sqlServer) ==> ACID
- NoSQL (redis. mongdb) ==>CAP
- CAP
CAP的三进二: CA、AP、 CP
- C (Consistency) 强一致性
- A (Availabilty)可用性
- P (Partition tolerance)分区容错性
- CAP核心
- CA:单点集群,满足-致性,可用性的系统,通常可扩展性较差
- CP: 满足- -致性,分区容错性的系统,通常性能不是特别高
- AP:满足可用性。分区容错性的系统,通常可能对一致性要求低一些
- 对比
对比/对象 | Eureka | Zookeeper |
---|---|---|
CAP | AP | CP |
5. Ribbno负载均衡
5.1 简述
- 定义
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套 客户端负载均衡的工具,Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址
- 负载均衡分类
- 集中式LB
即在服务的消费方和提供方之间使用独立的LB设施,如Nginx, 由该设施负责把访问请求通过某种策略转发至服务的提供方
- 进程式LB
将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器
5.2 开发
- 导入依赖
<!--Eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Ribbon负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 进行配置和扩展
server:
port: 80
#Eureka配置
eureka:
client:
register-with-eureka: false #不向Eureka中注册自己
service-url:
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
@Configuration
public class ConfigBean {//@Configuration=spring的 application.xml
//配置负载均衡实现RestTemplate
@Bean
@LoadBalanced //ribbon负载均衡的作用
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
//消费者 运行方式80可省略 例:localhost/consumer/dept/list
//Ribbon 和 Eureka 整合后,客户端可直接调用,不用关心Ip地址和端口号,会在定义的多个地址中随机选择
@SpringBootApplication
@EnableEurekaClient//在服务启动后,自动注册到Eureka注册中心中
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
- 开发
//声明提供者的localhost路径
//private static final String rest_url_prefix = "http://localhost:8001";
//通过ribbon去实现负载均衡,这里服务应该是一个变量,通过服务名来访问 *
private static final String rest_url_prefix = "http://SPRINGCLOUD-PROVIDER-DEPT";
- 修改算法
- 在不能被全局引入下创建RuleConfig
//自定义Ribbon配置的负载均衡类,客户端RibbonConfiguration中已存在的组件与FooConfiguration中的任何组件组成(后者通常会覆盖前者)
//自定义的组件请注意 它不在|程序的上下文的ComponentScan中,所以要放在单独的不重叠的包中
@Configuration
public class RuleConfig {
@Bean
public IRule myRule(){
//默认是轮询,现在我们自定义为DiyRandomRule 自定义负载均衡
return new DiyRandomRule();
}
}
- 更改算法
public class DiyRandomRule extends AbstractLoadBalancerRule {
//代码全是复制的 DiyRandomRule.class的,自定义负载均衡需要自己修改
//当前自定义负载均衡:
//每个服务访问5次。换下一个服务
//total=0,默认=0,如果=5,指向下一个服务节点
//index=0,默认0,如果total=5,则inedx+1
private int totla=0;//被调用的次数
private int currentIndex=0;//当前是谁在提供服务
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();//获得活着的服务
List<Server> allList = lb.getAllServers();//获得全部的服务
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
//int index = this.chooseRandomInt(serverCount);//生成区间随机数
//server = (Server) upList.get(index);//从活着的服务中,随机获取一个
//================自定义负载均衡算法==================
if(totla<5){
server = upList.get(currentIndex);
totla++;
}else{
totla=0;
currentIndex++;
if (currentIndex>=upList.size()){//当前节点大于活着的数量
currentIndex = 0;
}
server=upList.get(currentIndex);//从活着的服务中,获取指定的服务来进行操作
}
//====================================================
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
- 引用注解
//消费者 运行方式80可省略 例:localhost/consumer/dept/list
@SpringBootApplication
@EnableEurekaClient//在服务启动后,自动注册到Eureka注册中心中
//在微服务启动的时候就能去加载我们自定义Ribbon配置的负载均衡类,自定义为跳转5次切换节点
@RibbonClient(name="SPRINGCLOUD-PROVIDER-DEPT",configuration = RuleConfig.class)
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
6. Feign负载均衡
6.1 简述
- 定义
Feign旨在使编写Java Http客户端变得更容易
- Feign与Ribbon的区别
Ribbon和Feign都是用于调用其他服务的,不过方式不同。
不同点 | Ribbon | Feign |
---|---|---|
风格 | RestFul | 面向接口 |
启动类使用的注解 | @RibbonClient | @EnableFeignClients |
服务的指定位置 | Ribbon是在@RibbonClient注解上声明 | Feign则是在定义抽象方法的接口中使用@FeignClient声明 |
调用方式不同 | Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。 | Feign则是在Ribbon的基础上进行了一次改进,采用接口的方式,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建http请求。不过要注意的是抽象方法的注解、方法签名要和提供服务的方法完全一致 |
6.2 开发
- springcloud-api
- 导入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- DeptClientService.java
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@PostMapping("/dept/list")
public List<Dept> queryAll();
@GetMapping("/dept/add")
public boolean addDept(Dept dept);
}
- springcloud-consumer-dept-feign
- 导入依赖
<dependency>
<groupId>org.example</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- DeptConsumerController
@RestController
public class DeptConsumerController {
//Feign面向接口编程
//springcloud-api-feign 下的service
@Resource
private DeptClientService deptClientService =null;
//添加数据
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return deptClientService.addDept(dept);
}
//通过id查询
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return deptClientService.queryById(id);
}
//查询所有
@RequestMapping("/consumer/dept/list")
public List<Dept> queryAll(){
return deptClientService.queryAll();
}
}
- DeptConsumer_feign启动类
//消费者 运行方式80可省略 例:localhost/consumer/dept/list
@SpringBootApplication
@EnableEurekaClient //在服务启动后,自动注册到Eureka注册中心中
@EnableFeignClients(basePackages = {"com.lemon.springCloud"}) //Feign被扫描到
public class DeptConsumer_feign {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_feign.class,args);
}
}
7. Hystrix 服务熔断
7.1 简述
- 定义
分布式系统面临的问题: 复杂分布式结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失效,Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一 个依赖出问题的情况下, 不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
- 用处
- 服务降级
- 服务熔断
- 服务限流
- 接近实时的监控等等
- 服务熔断
熔断机制是对应雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况, 当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand.
7.2 服务熔断
- 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 进行配置或者扩展
- 配置文件
server:
port: 8082
mybatis:
type-aliases-package: com.xxy.cloud.pojo
mapper-locations: [classpath:mapper/*.xml]
spring:
application:
name: springcloud-provider-hystrix
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/temp1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
username: root
password: 'root'
druid:
db-type: com.alibaba.druid-spring-boot-starter
max-active: 20
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
instance:
#修改Eureka中status的默认描述信息。不配置默认为DESKTOP-XXX描述
instance-id: springcloud-server-provider
- 启动类@EnableHystrix
package com.xxy.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
/**
* @author xxy
* @version 1.0
* @date 2023-03-19-20:42
*/
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class UserProviderHystrix_8082 {
public static void main(String[] args) {
SpringApplication.run(UserProviderHystrix_8082.class,args);
}
}
- 开发controller
@RequestMapping(value = "/select/{id}",method = RequestMethod.GET)
@HystrixCommand(fallbackMethod = "hystrixGet")
public User seleteUserById(@PathVariable("id") Long id) {
User user = userService.selectUserById(id);
if (user == null) {
throw new RuntimeException("id=> "+ id+"不存在该用户,或者该信息无法找到");
}
return user;
}
public User hystrixGet(@PathVariable("id") Long id) {
return new User().setId(id).setName(id+"没有相关信息").setVersion("not at mysql");
}
- 输入
http://localhost:8082/user/select/数据库没有的id
进行测试
7.3 服务降级
被动服务熔断会服务降级,主动关闭服务也会服务降级,熔断机制是应对雪崩效应的一种微服务链路保护机制,当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,服务降级处理是在客户端实现完成的,与服务端没有关系
- 配置
#开启降级Feign Hystrix
feign:
hystrix:
enabled: true
- 在springcloud-api中或者新建的springcloud-api-feign项目中的service包中创建DeptClientServiceFallbackFactory降级服务类
//Hystrix 降级,当服务端关闭后的提示信息
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
@Override
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
@Override
public Dept queryById(Long id) {
return new Dept()
.setDeptno(id)
.setDname("id=>" +id+"没有对应的信息,客户端提供了降级的信息,这个服务现在已经关闭")
.setDb_source("已降级 未查找到数据");
}
@Override
public List<Dept> queryAll() {
return null;
}
@Override
public boolean addDept(Dept dept) {
return false;
}
};
}
}
- 增加注解@FeignClient(value = “SPRINGCLOUD-PROVIDER-DEPT”,fallbackFactory = DeptClientServiceFallbackFactory.class)
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@PostMapping("/dept/list")
public List<Dept> queryAll();
@PostMapping("/dept/add")
public boolean addDept(Dept dept);
}
123456789101112
7.4 Dashboard流监控
- 导包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--dashboard流监控-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 配置
#Hystrix的dashboard流监控 端口
server:
port: 9001
- 启动类@EnableHystrixDashboard
@SpringBootApplication
@EnableHystrixDashboard
public class UserConsumerDashboard_9001 {
public static void main(String[] args) {
SpringApplication.run(UserConsumerDashboard_9001.class,args);
}
}
- 在
springcloud-provider-hystrix
中启动类
package com.xxy.springcloud;
/**
* @author xxy
* @version 1.0
* @date 2023-03-19-20:42
*/
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
@EnableDiscoveryClient
public class UserProviderHystrix_8082 {
public static void main(String[] args) {
SpringApplication.run(UserProviderHystrix_8082.class,args);
}
//增加一个servlet,配合dashboard监控使用,固定的代码 http://localhost:8001/actuator/hystrix.stream访问监控
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
}
- 输入
localhost:8001/actuator/hystrix.stream
进行测试
8. Zuul路由网关
已经过时,了解思想即可,推荐GetWay
8.1 简述
- 定义
Zuul包含了对请求的路由和过滤两个最主要的功能,Zuul服务最终还是会注册进Eureka,代理+路由+过滤三大功能
- Zuul组件
- zuul-core–zuul核心库,包含编译和执行过滤器的核心功能
- zuul-simple-webapp–zuul Web应用程序示例,展示了如何使用zuul-core构建应用程序
- zuul-netflix–lib包,将其他NetflixOSS组件添加到Zuul中,例如使用功能区进去路由请求处理
- zuul-netflix-webapp–webapp,它将zuul-core和zuul-netflix封装成一个简易的webapp工程包
8.2 Zuul开发
- 导依赖
<!--Zuul路由网关 9527端口-->
<artifactId>springcloud/springcloud-zuul-9527</artifactId>
<!--Zuul路由网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 配置
可以在
C:\Windows\System32\drivers\etc\hosts
模拟zuul网关
127.0.0.1 www.lijie.com
server:
port: 9527
spring:
application:
name: springcloud-zuul
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
instance:
#修改Eureka中status的默认描述信息。不配置默认为DESKTOP-XXX描述
instance-id: zuul9527.com #自定义名称
prefer-ip-address: true #改为true后 Eureka中的status就会显示真实ip地址
info: #链接点开后显示的info信息
app.name: tizi => zuul test
company.name: tizi=> zuul.com
version.name: tizi.01
zuul:
routes:
mydept.serviceId: springcloud-provider-dept
#之前的查询链接地址 http://www.lijie.com:9527/springcloud-provider-dept/dept/get/1
#现在的查询链接地址,配置后为 http://www.lijie.com:9527/mydept/dept/get/1
#两者都皆可访问(原路径+现配路径)。配置自定义的前缀后 可不让客户端知道真实的ip地址
mydept.path: /mydept/**
#加上此配置后 原路径不能访问(springcloud-provider-dept/dept/get/6),只能通过自定义的规则路径访问。
#ignored-services: springcloud-provider-dept
#星号(*) 隐藏全部的项目真实名字
ignored-services: "*"
prefix: /li #设置公共的地址前缀 配置后链接为:www.lijie.com:9527/li/mydept/dept/get/11
9. SpringCloud config分布式配置中心
9.1 简述
- 定义
Spring Cloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置。
- 组成
Spring Cloud Config 分为服务端和客户端两部分;
服务端也称为分布式配置中心,它是一 个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密,解密信息等访问接口。
- 解决的问题
- 集中管理配置文件
- 不同环境,不同配置,动态化的配置更新,分环境部署,比如/dev /test/ /prod /beta /release
- 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息。
- 当配置发生变动时,服务不需要重启,即可感知到配置的变化,井应用新的配置
- 将配置信息以REST接口的形式暴露
9.2 config-server开发
-
新建gitee仓库
-
初始化git
# 显示当前的Git配置
$ git config --list
# 设置提交代码时的用户信息
$ git config --global user.name "[name]"
$ git config --global user.email "[email address]"
$ git clone "你的SSH地址"
- 新建application.yml文件
spring:
profiles:
active: dev
---
spring:
profiles: dev
application:
name: springcloud-config-dev
---
spring:
profiles: test
application:
name: springcloud-config-test
- 提交码云
GitBash打开命令工具
cd 至 springcloud-config
git add . 将文件添加到暂存区
git status 查看状态
git commit -m “第一次提交” 本地提交,-m为提交时写的信息
git push origin master 提交到远程的当前路径分枝
- 导入依赖
<?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>com.xxy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-config-server</artifactId>
<dependencies>
<!--springcloud-config的配置-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
- 配置application.yml
server:
port: 3344
spring:
application:
name: springcloud-config-server
#连接远程的仓库
cloud:
config:
server:
git:
# 通过 config-server可以连接到git,访问其中的资源以及配置
# skip-ssl-validation: true
uri: https://gitee.com/xxy8/springcloud-config.git #自己远程仓库的https地址
username: xxy8
password: 'xxy580108'
- 启动类加@EnableConfigServe
@SpringBootApplication
@EnableConfigServer
public class ConfigServer_3344 {
public static void main(String[] args) {
SpringApplication.run(ConfigServer_3344.class,args);
}
}
- 输入
localhost:3344/application-dev.yml
进行测试
9.3 config-client开发
- 新建config-client.yml文件
#启动环境选择的配置
spring:
profiles:
active: dev
#springboot启动多环境的配置
---
server:
port: 8201
#spring的配置
spring:
profiles: dev
application:
name: springcloud-config-client-dev
#Eureka的配置。 服务注册到Eureka中,需要一个路径地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
---
server:
port: 8202
#spring的配置
spring:
profiles: test
application:
name: springcloud-config-client-test
#Eureka的配置。 服务注册到Eureka中,需要一个路径地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
- 提交到码云
GitBash打开命令工具
cd 至 springcloud-config
git add . 将文件添加到暂存区
git status 查看状态
git commit -m “一次提交” 本地提交,-m为提交时写的信息
git push origin master 提交到远程的当前路径分枝
- 导入依赖
<?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>com.xxy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-config-client</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--springcloud-config启动的配置 和服务端的不同-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
</dependencies>
</project>
- 创建application.yml,并配置
#用户级别的配置 配置去读取谁
spring:
application:
name: springcloud-config-client-3355
- 创建bootstrap.yml,配置
# 系统级别的配置
spring:
cloud:
config:
name: config-client # 需要从git上读取的资源名称,不要后缀
profile: dev #dev环境端口:8201 test环境端口:8202
label: master #需要在git上的哪个分支拿
#连接到3344服务,中转站的形式连接服务端访问远程地址
uri: http://localhost:3344
- 启动类
package com.xxy.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author xxy
* @version 1.0
* @date 2023-03-21-23:32
*/
@SpringBootApplication
public class ConfigClient_8201 {
public static void main(String[] args) {
SpringApplication.run(ConfigClient_8201.class,args);
}
}
- Controller
package com.xxy.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xxy
* @version 1.0
* @date 2023-03-21-23:30
*/
//@Value为git上的client-config的值
@RestController
public class ConfigClientController {
@Value("${spring.application.name}")
private String applicationName;
@Value("${eureka.client.service-url.defaultZone}")
private String eurekaServer;
@Value("${server.port}")
private String port;
@RequestMapping("/config")
public String getConfig(){
return "applicationName: "+applicationName+
"eurekaServer: "+eurekaServer+
"port: "+port;
}
}
- 输入
http://localhost:8201/config
进行测试,结果为:
applicationName: springcloud-config-client-deveurekaServer: http://localhost:7001/eurekaport: 8201
9.4 实际开发
- 修改eureka配置文件,将配置加入码云中
- config-eureka.yml
spring:
profiles:
active: dev
---
server:
port: 7001
#spring的配置
spring:
profiles: dev
application:
name: springcloud-config-eureka
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,我的职责就是维护服务实例,并不需要去搜索服务
service-url:
#设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
---
server:
port: 7001
#spring的配置
spring:
profiles: test
application:
name: springcloud-config-eureka
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,我的职责就是维护服务实例,并不需要去搜索服务
service-url:
#设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- 将user:8081提供者配置文件改变
- config-user.yml
spring:
profiles:
active: dev
---
server:
port: 8081
mybatis:
type-aliases-package: com.xxy.cloud.pojo
mapper-locations: [classpath:mapper/*.xml]
spring:
profiles: dev
application:
name: springcloud-config-user
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/temp1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
username: root
password: 'root'
druid:
db-type: com.alibaba.druid-spring-boot-starter
max-active: 20
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
instance:
#修改Eureka中status的默认描述信息。不配置默认为DESKTOP-XXX描述
instance-id: springcloud-server-provider
---
server:
port: 8081
mybatis:
type-aliases-package: com.xxy.cloud.pojo
mapper-locations: [classpath:mapper/*.xml]
spring:
profiles: test
application:
name: springcloud-config-user
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/temp1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
username: root
password: 'root'
druid:
db-type: com.alibaba.druid-spring-boot-starter
max-active: 20
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
instance:
#修改Eureka中status的默认描述信息。不配置默认为DESKTOP-XXX描述
instance-id: springcloud-server-provider
- 提交到码云
GitBash打开命令工具
cd 至 springcloud-config
git add . 将文件添加到暂存区
git status 查看状态
git commit -m “一次提交” 本地提交,-m为提交时写的信息
git push origin master 提交到远程的当前路径分枝
- 新建项目,导入依赖
<?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>com.xxy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-config-eureka</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>3.0.4</version>
</dependency>
<!--springcloud-config启动的配置 和服务端的不同-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
</dependencies>
</project>
- applicaation.yml
spring:
application:
name: springcloud-config-eureka
- bootstrap.yml
# 系统级别的配置
spring:
cloud:
config:
name: config-eureka # 需要从git上读取的资源名称,不要后缀
profile: dev #dev环境端口:8201 test环境端口:8202
label: master #需要在git上的哪个分支拿
#连接到3344服务,中转站的形式连接服务端访问远程地址
uri: http://localhost:3344
-
其他复制 springcloud-eureka所有的内容,除配置文件,进行测试
http://localhost:3344/config-eureka-dev.yml
,http://localhost:7001/
-
复制springcloud-provider-user所有内容
-
修改application.yml
spring:
application:
name: springcloud-config-user
- 新增bootstrap.yml文件
# 系统级别的配置
spring:
cloud:
config:
name: config-user # 需要从git上读取的资源名称,不要后缀
profile: dev #dev环境端口:8201 test环境端口:8202
label: master #需要在git上的哪个分支拿
#连接到3344服务,中转站的形式连接服务端访问远程地址
uri: http://localhost:3344
- 分别输入
http://localhost:3344/config-user-dev.yml
,http://localhost:7001/
,localhost:8081/user/select/
进行测试,能够显示结果说明Springcloud config成功
10. 总结
本文以Springcloud Netflix为例子主要了解了微服务的网关 、服务注册与发现、负载均衡(通信)、服务熔断,其他的像监控、Spring Cloud Config,这些,其他微服务像Spring Alibaba可以以此为例子学习和对比。