Spring全家桶之SpringCloud——高级阶段(中)

SpringCloud高级阶段中

SpringCloud高级阶段上 传送门
第一章 负载均衡Ribbon
第二章 声明式调用Feign
第三章 服务容错保护Hystrix

SpringCloud高级阶段中(当前所在位置)
第四章 如何设计微服务
第五章 服务网关Zuul
第六章 分布式配置中心

SpringCloud高级阶段下 传送门
第七章 消息总线Bus
第八章 消息驱动Stream
第九章 分布式服务跟踪Sleuth

第四章 如何设计微服务

一、微服务常用的六种设计模式

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

二、 微服务设计模式实战

需求分析

如下图所示:
模拟电商项目中的订单模块, 因此需要添加模拟登陆 ,浏览商品 ,支付功能 ,订单功能等.
使用的最核心的设计模式为代理设计模式 ,通过Consumer对用户进行代理来进行相关的操作
在这里插入图片描述

数据库设计

  1. User 表

用户表,存放用户的相关属性,手动添加相关数据

CREATE TABLE `user` (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
  `password` varchar(50) NOT NULL COMMENT '密码',
  `email` varchar(50) NOT NULL COMMENT 'email',
  `deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT ' 删除标志,默认 0 不删除,1 删除',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户表';

  1. Product 表

产品表,存放产品的相关属性 , 手动添加相关数据

CREATE TABLE `product` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL COMMENT '产品名称',
  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '产品状态:0 待 审,1 上架,2 下架,3 停售,4 测试',
  `price` int(10) NOT NULL COMMENT '产品价格 单位分',
  `detail` text COMMENT '产品详情',
  `deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT ' 删除标志,默认 0 不删除,1 删除',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更 新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='产品信息';

  1. Orders 表

订单表,存放订单的相关信息 , 手动添加相关数据

CREATE TABLE `orders` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `product_id` int(10) NOT NULL DEFAULT '0' COMMENT '产品 ID',
  `price` int(10) DEFAULT '0' COMMENT '价格',
  `user_id` int(10) DEFAULT '0' COMMENT '用户账号 ID',
  `trade_id` int(10) DEFAULT '0' COMMENT '交易号 ID',
  `trade_status` tinyint(1) DEFAULT '0' COMMENT '支付状态 0=未支付 \r\n\r\n \r\n \r\n1=已支付',
  `deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT ' 删除标志,默认 0 不删除,1 删除',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更 新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

4 Trade 表

交易表,存放交易的相关信息 , 手动添加相关数据

CREATE TABLE `trade` (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'IID',
  `order_id` int(10) NOT NULL COMMENT '订单 ID',
  `user_id` int(10) NOT NULL COMMENT '用户 ID',
  `price` int(10) NOT NULL COMMENT '支付价',
  `pay_status` tinyint(4) NOT NULL COMMENT '1 未付款 2 付款中 3 付款失败 4 付款完成',
  `pay_type` tinyint(4) NOT NULL COMMENT '支付类型:1-支付宝支付, 2-网银在线,3-银联,4-微信支付',
  `gateway_pay_num` varchar(30) DEFAULT NULL COMMENT '网关支 付流水号',
  `gateway_pay_time` datetime DEFAULT NULL COMMENT '网关支付 时间',
  `gateway_pay_price` int(10) NOT NULL DEFAULT '0' COMMENT '网关 实际支付金额',
  `deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT ' 删除标志,默认 0 不删除,1 删除',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更 新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='交易';

product服务

在这里插入图片描述
1.官网快速构建产品服务的接口项目,添加相关坐标

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.7.RELEASE</version>
	</parent>
<!-- SpringBoot配套的运行环境,一定要加上,不加会报错!!! -->
	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
	</properties>

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

2.创建产品服务的提供者项目,添加相关坐标
勿忘添加服务接口项目的坐标

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.7.RELEASE</version>
	</parent>
	<!-- SpringBoot配套的运行环境,一定要加上,不加会报错!!! -->
	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
	</properties>

	<dependencies>
		<!-- springBoot 的启动器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- thymeleaf -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>

		<!-- Mybatis启动器 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.1.1</version>
		</dependency>
		<!-- mysql数据库驱动 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<!-- druid数据库连接池 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.0.9</version>
		</dependency>
		<!-- devtools:热部署时修改代码重新加载,无需重启启动器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<!-- 表示依赖不向下传递 -->
			<optional>true</optional>
		</dependency>



		<!-- 添加服务接口的坐标 -->
		<dependency>
			<groupId>ah.szxy.springcloud</groupId>
			<artifactId>E-Book-Trade-Service</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
	</dependencies>

3.修改全局配置文件application.yml的参数

项目名,
jdbc数据库连接参数,
该项目的端口号,
mybatis参数配置中实体类所在包
mapper.xml配置文件所在地址
Eureka注册中心地址,可以不配置,但需要将参数注释

spring:
  application:
    name: E-Book-Product-Provider
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/book-product?useUnicode=true&characterEncoding=gbk&useJDBCCompliantTimezoneShift=true&serverTimezone=UTC
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource

server:
  port: 8001
  compression:   #springboot的gzip配置
    enabled: true   #是否启用压缩  
    mime-types:    #配置压缩支持的 MIME TYPE
    - application/json,application/ xml,text/html,text/xml,text/plain
    
mybatis:
  type-aliases-package: ah.szxy.product.pojo
  mapper-locations:
  - classpath:ah/szxy/product/mapper/*.xml 

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

4.使用Mybatis逆向工程生成实体类,mapper接口与mapper.xml文件
点击查看MyBatis Generator( 逆向工程以及源码分析 )

5.将逆向工程生成的实体类放入服务接口项目中,并编写业务层访问代码
在这里插入图片描述

/**
 * 产品服务接口
 * @author chy
 *
 */
@RequestMapping("/product")
public interface ProductService {
	
	@RequestMapping(value="/find",method=RequestMethod.GET)
	public List<Product> findAll();
}

6.将逆向工程生成的Mapper接口与Mapper映射配置文件放入服务提供者项目下

在这里插入图片描述

7.业务层接口实现类,作用是调用Mapper接口,进而实现对数据库的查询操作

/**
 * 这里通过对mapper的操作实现对数据库的操作-查询所有
 * @author chy
 *
 */
@Service
public class ProductServiceImpl {
	
	@Autowired
	private ProductMapper mapper;
	
	public List<Product> findAll(){
		
		ProductExample example = new ProductExample();
		return this.mapper.selectByExampleWithBLOBs(example);//查询的条件中带有大字段
	}
}

8.Controller
注意:
1.需要实现服务接口项目中的相关项目接口
2.@RestController ,会在前端页面返回Json串

@RestController
public class ProductController implements ProductService{
	
	@Autowired
	private ProductServiceImpl productServiceImpl;
	
	@Override
	public List<Product> findAll() {

		return this.productServiceImpl.findAll();
	}
	
}

返回结果类似下图
在这里插入图片描述

根据接product服务,写出用户,订单,交易服务

创建消费者服务,实现消费者代理对其他服务的调用

1.创建项目,修改pom文件
因为继承服务接口项目中的接口,所以需要添加所有服务接口项目的坐标

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.7.RELEASE</version>
	</parent>
<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
	</properties>

	<dependencies>
		<!-- springBoot 的启动器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		
		<!-- 添加Feign的坐标 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
		
		<!-- 添加4个服务接接口项目的坐标,通过这些调用相关的服务 --> 
		<dependency>
			<groupId>ah.szxy.springcloud</groupId>
			<artifactId>E-Book-User-Service</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		<dependency>
			<groupId>ah.szxy.springcloud</groupId>
			<artifactId>E-Book-Trade-Service</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		<dependency>
			<groupId>ah.szxy.springcloud</groupId>
			<artifactId>E-Book-Product-Service</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		<dependency>
			<groupId>ah.szxy.springcloud</groupId>
			<artifactId>E-Book-Order-Service</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		
		<!-- devtools,热部署刷新工具 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<!-- 表示依赖不向下传递 -->
			<optional>true</optional>
		</dependency>
		
	</dependencies>

2.修改全局配置文件application.yml

spring:
  application:
    name: E-Book-Consumer
server:
  port: 8888


eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

3.创建四个消费者服务接口,继承服务接口项目中的接口

/**
 * 调用订单服务
 * @FeignClient 声明式调用服务,需要指明提供者的名称
 * 继承服务接口项目的接口
 * 
 * @author chy
 *
 */
@FeignClient("E-Book-Order-Provider")   
public interface ConsumerOrderService extends OrderService{

}

/**
 * 调用产品服务
 * @FeignClient 声明式调用服务,需要指明提供者的名称
 * 继承服务接口项目的接口
 * 
 * @author chy
 *
 */
@FeignClient("E-Book-Product-Provider")
public interface ConsumerProductService extends ProductService{

}

/**
 * 调用交易服务
 * @FeignClient 声明式调用服务,需要指明提供者的名称
 * 继承服务接口项目的接口
 * 
 * @author chy
 *
 */
@FeignClient("E-Book-Trade-Provider")
public interface ConsumerTradeService extends TradeService {

}
/**
 * 调用用户服务
 * @FeignClient 声明式调用服务,需要指明提供者的名称
 * 继承服务接口项目的接口
 * 
 * @author chy
 *
 */
@FeignClient("E-Book-User-Provider")
public interface ConsumerUserService extends UserService {

}

4.将所有的业务逻辑提升到Controller ,实现相关的业务逻辑

/**
 * 创建订单
 * @author chy
 *
 */
@RestController
public class ConsumerController {
	
	@Autowired
	private ConsumerOrderService orderService;
	@Autowired
	private ConsumerProductService productService;
	@Autowired
	private ConsumerUserService userService;
	@Autowired
	private ConsumerTradeService tradeService;
	
	/**
	* 模拟内容: 登录 查看产品 下订单
	* 1. 测试登录 账号 admin admin
	* 2. 查看所有产品列表
	* 3. 选第一款产品,下订单
	* 4. 实现订单交易支付
	* 5. 查看所有的订单信息
	*/
	@RequestMapping(value="/create",method=RequestMethod.GET)
	public List<Orders> createOrder() {
		System.out.println("++++++++++创建订单是测试是否登录++++++++");
		//创建订单是测试是否登录
		Integer userid = this.login();
		System.out.println(userid);
		System.out.println("++++++++++++++++++");
		
		System.out.println("++++++++++登陆成功后,查看所有商品+++++++++");
		//登陆成功后,查看所有商品
		List<Product> list = this.productService.findAll();
		for(Product product:list) {
			System.out.println(product.getName());
		}
		System.out.println("+++++++++++++++++++");
		
		System.out.println("+++++++++下单++++++++++");
		//选择第一款商品下单
		Product product = list.get(0);
		Integer orderid=1004;
		//创建订单
		Orders order = new Orders();
		order.setId(orderid);
		order.setUserId(userid);
		order.setProductId(product.getId());
		order.setPrice(product.getPrice());
		order.setDeleted((byte) 0);//0不删除,1删除
		//调用Order服务完成持久化订单
		Integer result = this.orderService.addOrder(order);
		System.out.println("交易订单结果"+result);
		System.out.println("++++++++++++++++++++++++");
		System.out.println("+++++++++++创建交易订单+++++++++++++");
		
		Trade trade = new Trade();
		trade.setOrderId(orderid);
		trade.setUserId(userid);
		trade.setPrice(order.getPrice());
		trade.setPayStatus((byte) 4);//'1 未付款 2 付款中 3 付款失败 4 付款完成',
		trade.setPayType((byte) 4);//'支付类型:1-支付宝支付, 2-网银在线,3-银联,4-微信支付',
		trade.setGatewayPayNum(new Date().getTime()+"");
		trade.setGatewayPayPrice(order.getPrice());
		trade.setGatewayPayTime(new Date());
		trade.setDeleted((byte) 0);
		this.tradeService.addTrade(trade);
		
		//查询所有订单并返回
		List<Orders> orderlist = this.orderService.findAll();
		return orderlist;
	}
	
	/**
	 * 用户登陆
	 * @return
	 */
	private Integer login() {
		String userName="admin";
		String password="admin";
		User user = this.userService.userLogin(userName, password);
		if (user !=null && user.getUserName().length() >=0) {
			System.err.println("登陆成功");
			return user.getId();
		}
		System.out.println("登陆失败");
		return null;
	}
	
	
}

5.启动类

因为使用声明式调用,需要添加@EnableFeignClients

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

测试结果
在这里插入图片描述

服务调用服务(Trade去调用Order进行查询和更新)

1.修改Trade的pom文件
添加Order接口项目的坐标
添加Feign的坐标

<!-- 添加Order-Service坐标 -->
		<dependency>
			<groupId>ah.szxy.springcloud</groupId>
			<artifactId>E-Book-Order-Service</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		
		<!-- 添加Feign的坐标 ,导入后需要修改启动类 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>

2.添加提供者的代理消费接口

@FeignClient("E-Book-Order-Provider")  //接口不允许多类继承,而接口可以多继承接口
public interface ProviderOrderService extends OrderService{

}

3.添加消费者添加的方法,在这里调用Order的服务,查询并且修改Order
需要在Order接口项目中添加接口,提供者项目中创建实现类以及Controller方法(查询,更新)

	@Override
	public void addTrade(@RequestBody Trade trade) {
		//添加交易信息
		this.tradeServiceImpl.addTrade(trade);
		
		//根据id查询订单
		Orders order = orderService.findOrderById(trade.getOrderId());
		//order.setId(trade.getId());
		order.setTradeId(trade.getId());
		//更新订单(修改了订单id)
		this.orderService.updateOrder(order);
		
	}

查询和更新接口,其他省略

//根据订单id查询订单
	@RequestMapping(value="/findById",method=RequestMethod.GET)
	public Orders findOrderById(@RequestParam("orderid")Integer orderid);
	
	//更新订单
	@RequestMapping(value="update",method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE)
	public void updateOrder(@RequestBody Orders order);

3.启动类,需要额外添加@EnableFeignClients ,表示将要调用其他服务

@SpringBootApplication
@EnableEurekaClient
@MapperScan("ah.szxy.trade.mapper")//只能添加Mapper所在的包,而不是具体的类
@EnableFeignClients
public class TradeProviderApp {
	public static void main(String[] args) {
		SpringApplication.run(TradeProviderApp.class, args);
	}
}

功能思路

  1. 用户登录,调用user-provider实现登录。
  2. 查询商品:调用product-provider浏览商品
  3. 下订单:接受到请求后创建订单对象,填入基本信息,同时创建trade对象,设置关联关系。
    保存值数据库,在返回订单列表
  4. 支付:接受到请求后根据用户查找到未支付的订单order,在根据订单中的tradeid获取trade对象,修改trade和order信息。更新数据库,上述步骤在trade-provider中实现,创建一个接口继承orderserviceapi,使用feign调用。
    注:需要在各个provider中添加方法。
    接受参数是一定要是用 使用@RequsetParam注解,且一定要加参数。

第五章 服务网关Zuul

一、 什么是网关服务

什么是API网关
API网关是一个反向路由:屏蔽内部细节,为调用者提供统一入口,接收所有调用者请求,通过路由机制转发到服务实例。
API网关是一组“过滤器”集合:可以实现一系列与核心业务无关的横切面功能,如安全认证、限流熔断、日志监控。
在这里插入图片描述

二、 编写网关服务入门案例

1.创建项目,修改pom文件

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.7.RELEASE</version>
	</parent>
<!-- SpringBoot配套的运行环境,一定要加上,不加会报错!!! -->
	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
	</properties>
	<dependencies>
		<!-- devtools,热部署刷新工具 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<!-- 表示依赖不向下传递 -->
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<!-- 网关服务 -->
		<dependency>
		  <groupId>org.springframework.cloud</groupId>
		  <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>
	</dependencies>
	
	<dependencyManagement>
	<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

2.修改全局配置文件

spring:
  application:
    name: Zuul-Gateway
    
server:
  port: 9999

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

# URL 匹配关键字,如果包含path就跳转到指定的 URL 中
zuul:   #配置路由规则
  routes:
    E-Book-Product-Provider:   #此处为网关代理的服务名称
      path: /E-Book-Product-Provider/**
      url: http://localhost:8001/

3.启动类
添加@EnableZuulProxy注解

@SpringCloudApplication
@EnableZuulProxy
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

访问路径

http:// 网关服务地址 :网关服务端口 /访问的服务名称 /访问服务的接口地址

在这里插入图片描述
注:path中符号的含义

符号含义
/?匹配一个字符
/*匹配任意字符,但只能匹配单层路径
/ **匹配任意字符,可以匹配多层路径

zuul.routs.name.path中的name可以变更,通常使用服务名。

路由规则总结

1.通过url:
http://localhost:9999/suibian/product/find

	zuul:
	  routes:
	     E-Book-Product-Provider:
	      path: /suibian/**
	      url: http://localhost:8001/

2.通过服务名, service-id为服务名
http://localhost:9999/suibian/product/find

	zuul:
	  routes:
	    E-Book-Product-Provider:
	      path: /suibian/**
	      service-id: E-Book-Product-Provider

3.通过服务名(简化)
http://localhost:9999/suibian/product/find

zuul:
  routes:
    E-Book-Product-Provider:
      path: /suibian/**

不指定service-id,但要求zuul.routs.name.path中的name为服务名。

4.路由排除法

	zuul:
	    ignored-services:  #排除知道服务。也可以排除所有服务/*,可以同routes添加不排除的服务
	    - /*               # E-Book-Product-Provider
	    ignored-patterns:  #排除指定路径 使用符号统配
	    - /*/findAll

5.添加前缀 , 访问时服务路径前必须添加前缀
http://localhost:9999/sui/bian/product/find

zuul:
  prefix: /sui
  routes:
     E-Book-Product-Provider:  #必须是服务名
             path: /bian/** 

三、 自定义网关过滤器

1.复制上方案例,添加日志配置文件logback.xml

<?xml version="1.0" encoding="UTF-8" ?>
 <configuration>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->  
    <property name="LOG_HOME" value="${catalina.base}/logs/" />  
    <!-- 控制台输出 -->   
    <appender name="Stdout" class="ch.qos.logback.core.ConsoleAppender">
       <!-- 日志输出编码 -->  
        <layout class="ch.qos.logback.classic.PatternLayout">   
             <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
            </pattern>   
        </layout>   
    </appender>   
    <!-- 按照每天生成日志文件 -->   
    <appender name="RollingFile"  class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/server.%d{yyyy-MM-dd}.log</FileNamePattern>   
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>   
        <layout class="ch.qos.logback.classic.PatternLayout">  
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
            </pattern>   
       </layout> 
        <!--日志文件最大的大小-->
       <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
         <MaxFileSize>10MB</MaxFileSize>
       </triggeringPolicy>
    </appender>     

    <!-- 日志输出级别 -->
    <root level="info">   
        <appender-ref ref="Stdout" />   
        <appender-ref ref="RollingFile" />   
    </root> 



<!--日志异步到数据库 -->  
<!--     <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
        日志异步到数据库 
        <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
           连接池 
           <dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
              <driverClass>com.mysql.jdbc.Driver</driverClass>
              <url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
              <user>root</user>
              <password>root</password>
            </dataSource>
        </connectionSource>
  </appender> -->

</configuration>

2.修改全局配置文件

spring:
  application:
    name: Zuul-Gateway-Filter
    
server:
  port: 9999

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

# URL 匹配关键字,如果包含path就跳转到指定的 URL中
zuul:   #配置路由规则
  routes:
    E-Book-Product-Provider:
      path: /E-Book-Product-Provider/**
      url: http://localhost:8001/

3.创建过滤器
注意所导的包

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

@Component
public class MyFilter extends ZuulFilter{
	
	private Logger log=LoggerFactory.getLogger(MyFilter.class);

	/**
	 * 过滤逻辑
	 */
	@Override
	public Object run() throws ZuulException {
		
		RequestContext rc=RequestContext.getCurrentContext();
		HttpServletRequest req = rc.getRequest();
		log.info("Filter:method:{}+url:{}",req.getMethod(),req.getRequestURL().toString() );
		return null;
	}

	/**
	 * 是否开启过滤
	 */
	@Override
	public boolean shouldFilter() {
		// TODO Auto-generated method stub
		return true;
	}

	/**
	 * 拦截优先级   数字越小越高
	 */
	@Override
	public int filterOrder() {
		// TODO Auto-generated method stub
		return 0;
	}
	

	/**
	 * 拦截器类型
	 * PRE过滤器:是在请求路由到具体服务之前执行的,可以做安全验证,如身份验证,参数验证。
	*ROUTING过滤器:它用于将请求 路由到具体的微服务实例。默认使用Http Client进行网络请求。
	*POST过滤器:在请求已被路由到微服务后执行的。可用作收集统计信息、指标,以及将响应传输到客户端。
	*ERROR过滤器:在其他过滤器发生错误时执行。
    *只能小写
	 */
	@Override
	public String filterType() {
		// TODO Auto-generated method stub
		return "pre";
	}
}

运行启动器, 测试结果
在这里插入图片描述

过滤器类型(需要小写)
在这里插入图片描述

Zuul请求的声明周期(结合上图来看)

在这里插入图片描述

采用网关过滤器实现权限验证

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

import io.micrometer.core.instrument.util.StringUtils;

/**
 * 简单的登录权限校验
 * @author Administrator
 *
 */
@Component
public class TokenFilter extends ZuulFilter{
	
	private static final Logger log=LoggerFactory.getLogger(TokenFilter.class);

	/**
	 * 过滤逻辑
	 */
	@Override
	public Object run() throws ZuulException {
		
		RequestContext rc=RequestContext.getCurrentContext();
		HttpServletRequest req = rc.getRequest();
		String token = req.getParameter("token");
		if(StringUtils.isEmpty(token)) {
			//未登录
			log.warn("未登录!!!!");
			rc.setSendZuulResponse(false);//设置不向下传递,拦截不通过
			rc.setResponseStatusCode(401);
			rc.setResponseBody("未登录!!请先登录");
			rc.getResponse().setContentType("text/html;charset=utf-8");
			
		}else {
			log.info("已登录,通过过滤器!!!");
			
		}
		return null;
	}

	/**
	 * 是否开启过滤
	 */
	@Override
	public boolean shouldFilter() {
		return true;
	}

	/**
	 * 拦截优先级   数字越小越高
	 */
	@Override
	public int filterOrder() {
		return 0;
	}
	

	/**
	 * 拦截器类型
	 * PRE过滤器:是在请求路由到具体服务之前执行的,可以做安全验证,如身份验证,参数验证。
	*ROUTING过滤器:它用于将请求 路由到具体的微服务实例。默认使用Http Client进行网络请求。
	*POST过滤器:在请求已被路由到微服务后执行的。可用作收集统计信息、指标,以及将响应传输到客户端。
	*ERROR过滤器:在其他过滤器发生错误时执行。
	 */
	@Override
	public String filterType() {
		//只能是小写
		return "pre";
	}
}

采用网关过滤器对系统异常同一处理

  1. 创建异常过滤器
    在过滤器逻辑中自定义了一个异常RuntimeException(“运行异常”)
@Component
public class ErrorMyFilter extends ZuulFilter{
	
	private Logger log=LoggerFactory.getLogger(ErrorMyFilter.class);

	/**
	 * 过滤逻辑
	 */
	@Override
	public Object run() throws ZuulException {
		
		RequestContext rc=RequestContext.getCurrentContext();
		HttpServletRequest req = rc.getRequest();
			//http://localhost:9999/E-Book-Product-Provider/product/find?token=suibian
			log.info("------网关过滤器拦截异常------");
			throw new RuntimeException("运行异常");
			
	}
	/**
	 * 是否开启过滤
	 */
	@Override
	public boolean shouldFilter() {
		// TODO Auto-generated method stub
		return true;
	}

	/**
	 * 拦截优先级   数字越小越高
	 */
	@Override
	public int filterOrder() {
		// TODO Auto-generated method stub
		return 0;
	}
	

	/**
	 * 拦截器类型
	 * PRE过滤器:是在请求路由到具体服务之前执行的,可以做安全验证,如身份验证,参数验证。
	*ROUTING过滤器:它用于将请求 路由到具体的微服务实例。默认使用Http Client进行网络请求。
	*POST过滤器:在请求已被路由到微服务后执行的。可用作收集统计信息、指标,以及将响应传输到客户端。
	*ERROR过滤器:在其他过滤器发生错误时执行。
    *只能小写
	 */
	@Override
	public String filterType() {
		// TODO Auto-generated method stub
		return "error";
	}
}

2.创建异常处理的controller

@RestController
public class ExceptionHandler implements ErrorController {

	@Override
	public String getErrorPath() {
		return "/error";
	}
	
	@RequestMapping("/error")
	public String handler() {
		return "出错了!!!!";
	}

}

四、 网关容错

一. zuul 和 hystrix 无缝结合
在 zuul 的 jar 包中包含了 hystrix 的 jar 包。所以我们不需要在项目中添加 Hystrix 的坐标 (SpringBoot2.0以上版本需要在配置文件中启用hystrix.stream)

management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream 
  1. 启动并访问一个服务,然后使用网关访问这个服务

  2. 访问网关服务的数据监控流

    http://localhost:9999/actuator/hystrix.stream

  3. 启动 dashboard 服务通过可视化界面查看监控数据
    在这里插入图片描述

二. 在网关中实现对服务降级处理

  1. 创建项目
  2. 导入依赖(zuul)
  3. 修改配置文件(项目名、端口、注册中心)
spring:
  application:
    name: Zuul-Gateway-FallBack
    
server:
  port: 9020

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

zuul:   #配置路由规则
  routes:
    E-Book-Product-Provider:
      path: /E-Book-Product-Provider/**
      url: http://localhost:8001/
  1. 添加fallback类
    实现ZuulFallbackProvider接口**(2.0版本后实现FallbackProvider接口)**
/**
 * 实现FallbackProvider接口,实现服务降级
 * 
 * 1.添加@Component注解
 * 2.getRoute方法返回监控的服务名称
 * 3.FallbackProvider
 * 
 * @author Administrator
 *
 */
@Component
public class ProductProviderFallback implements FallbackProvider {

	/**
	 * 对指定的服务提供降级处理
	 */
	@Override
	public String getRoute() {
		return "E-Book-Product-Provider";
	}

	/**
	 * 设置降级后返回的响应
	 */
	@Override
	public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
		return new ClientHttpResponse() {
			
			/**
			 * 响应头
			 */
			@Override
			public HttpHeaders getHeaders() {
				HttpHeaders hander=new HttpHeaders();
				hander.setContentType(MediaType.APPLICATION_JSON_UTF8);
				return hander;
			}
			/**
			 * 响应体
			 */
			@Override
			public InputStream getBody() throws IOException {
				String content="请求服务不可达!请联系管理员!";
				return new ByteArrayInputStream(content.getBytes());
			}
			/**
			 * 状态码:String类型
			 */
			@Override
			public String getStatusText() throws IOException {
				// TODO Auto-generated method stub
				return getStatusCode().getReasonPhrase();
			}
			/**
			 * 状态码:HttpStatus类型
			 */
			@Override
			public HttpStatus getStatusCode() throws IOException {
				return HttpStatus.OK;
			}
			/**
			 * 状态码:int类型
			 */
			@Override
			public int getRawStatusCode() throws IOException {
				// TODO Auto-generated method stub
				return getStatusCode().value();
			}
			
			/**
			 * 关闭
			 */
			@Override
			public void close() {
				
			}
		};
	}
}

启动类

@SpringCloudApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

测试结果
启动一个服务,然后通过网关服务进行访问 ,最后关闭服务, 刷新网关服务页面,查看页面输出结果

在这里插入图片描述

五、 在高并发情况下,网关实现限流达到自我保护

  1. 创建项目 ,导入依赖
    注意额外添加了限流的jar包redis的坐标
	<!-- SpringBoot配套的运行环境,一定要加上,不加会报错!!! -->
	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
	</properties>
	<dependencies>
		<!-- devtools,热部署刷新工具 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<!-- 表示依赖不向下传递 -->
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<!-- 网关服务 -->
		<dependency>
		  <groupId>org.springframework.cloud</groupId>
		  <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>
		
		
		<!-- 网关限流 -->
		<dependency>
		    <groupId>com.marcosbarbero.cloud</groupId>
		    <artifactId>spring-cloud-zuul-ratelimit</artifactId>
		    <version>2.2.3.RELEASE</version>
		</dependency>
		<!-- 限流用到了redis进行缓存 -->
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
	</dependencies>

2.修改全局配置值文件

spring:
  application:
    name: Zuul-getway-ratelimit
  redis:
  #redis单机配置
    host: 47.98.169.238
    port: 6379
#redis连接池配置
    jedis:
      pool:
        max-idle: 10
        min-idle: 5
        max-active: 100
        max-wait: 3000
server:
  port: 8888
  
eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

#配置路由规则
zuul:
  routes:
    E-Book-Product-Provider:
      path: /suibian/**

  ratelimit:
    enabled: true   #开启限流
    #全 局 限 流
    default-policy-list:       #全局配置  
    - limit: 10    #访问次数
      quota: 30     #访问总时间
      refresh-interval: 60      #时间间隔
    # 即在时间间隔内 访问的次数 总时间小于 访问总时间 就会被限制
      type:
      - origin    #对ip进行限制
    repository: redis    #数据存储方式,默认为内存存储
    #指定服务限流(局部限流)
#    policy-list:
#      E-Book-Product-Provider:  #被限流的服务名
#      - limit: 10
#        quota: 30
#        refresh-interval: 60
#        type:
#        - url
#      repository: redis    #数据存储方式,默认为内存存储

#开启监控端点   http://ip:port/actuator/hystrix.stream    需要actuatorjar包
#management:
#  endpoints:
#    web:
#      exposure:
#        include: hystrix.stream 
        

补充 :超时参数介绍
在这里插入图片描述

3.测试
在60s内访问10次,且十次访问在30s内,被限流,返回429错误

在这里插入图片描述

4.可以通过异常处理类处理限流异常(429),返回指定的页面,创建友好的交互

六、zuul超时调优图解

背景介绍
hystrix的超时时间为1s,而ribbon为5s,假设请求在1s内没有处理完,就会timeout。
我们将hystrix的超时时间调高,避免timeout。
但ribbon的超时时间应该小于hystrix,在集群环境下,给充足的时间让ribbon调用集群中其他服务。

在这里插入图片描述

情景模拟
被hystrix监控的服务在查询数据库时,由于数据量大而请求响应时间大于1s,导致返回超时问题

异常错误模拟
令被监控的服务休眠两秒 ,出现如下错误在这里插入图片描述

解决方案
1.创建网关项目 ,修改pom

<!-- SpringBoot配套的运行环境,一定要加上,不加会报错!!! -->
	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
	</properties>
	<dependencies>
			<!-- 表示依赖不向下传递 -->
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<!-- 网关服务 -->
		<dependency>
		  <groupId>org.springframework.cloud</groupId>
		  <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>
	</dependencies>

2.修改全局配置文件

设置Ribbo和hystrix的超时时限

spring:
  application:
    name: Zuul-Gateway-Timeout
    
server:
  port: 9999

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

#http://localhost:9999/suibian/product/find  
zuul:
  routes:
    E-Book-Product-Provider:
      path: /suibian/**

#hystrix的超时时限  
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 8000 
#ribbon的超时时限  
ribbon:
  ReadTimeout: 5000
  ConnectTimeout: 5000
             
management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream 

3.启动类

@SpringCloudApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

测试结果
访问刚才出现超时的页面,发现Zuul超时问题得以解决

第六章 分布式配置中心

一、 为什么需要使用配置中心

  1. 服务配置的现状
    在这里插入图片描述

  2. 常用的配置管理解决方案的缺点

在这里插入图片描述

  1. 为什么要使用SpringCloud Config配置中心
    在这里插入图片描述

  2. SpringCloud Config配置中心解决了什么问题
    在这里插入图片描述

二、编写配置中心入门案例

前提
使用码云作为git仓库。先注册码云账号,创建一个仓库即可,
下面会用到仓库的全网访问的url

在这里插入图片描述

创建配置中心server端

1.创建SpringCloud项目 ,修改pom文件
最重要的就是配置中心server 的坐标

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.7.RELEASE</version>
	</parent>
<!-- SpringBoot配套的运行环境,一定要加上,不加会报错!!! -->
	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
	</properties>
	<dependencies>
		<!-- devtools,热部署刷新工具 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<!-- 表示依赖不向下传递 -->
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- Eureka注册中心 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<!-- 网关服务 -->
		<dependency>
		  <groupId>org.springframework.cloud</groupId>
		  <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>
		
		<!-- 配置中心server -->
		<dependency>
	      <groupId>org.springframework.cloud</groupId>
	      <artifactId>spring-cloud-config-server</artifactId>
	    </dependency>
	</dependencies>
	
	<dependencyManagement>
	<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

2.修改全局配置文件 application.yml
注意在使用时, 应用名(spring.application.name)不能与Eureka注册中心的其他服务的应用名相同 ,否则会访问不到码云上的配置文件

spring:
  application:
    name: config-server-Git  
  cloud:
    config:
      server:
        git:    #Git 配置 
          uri: https://gitee.com/TimePause/SpringCloudConfig   #码云仓库url
          username:       #码云账号
          password:       #码云密码
        
    
    
server:
  port: 9090

eureka:
  client:
    serviceUrl:
      defaultZone:    #Eureka注册中心地址

3.创建4个临时配置文件 ,然后上传到码云仓库中 ,再把项目中的这些临时配置文件移除
在这里插入图片描述

4 .编写启动类并启动
主要添加了 @EnableConfigServer注解

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

测试结果
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

配置中心配置文件的命名与访问规则

在这里插入图片描述

注意 :
application为即将对其配置的服务的服务名
主干访问正常访问 ,分支访问需要加上分支的名称

创建配置中心Client端

1.复制上个项目 ,修改pom文件
将原来配置中心的server的坐标换成client的坐标

<!-- 配置中心client -->
		<dependency>
		  <groupId>org.springframework.cloud</groupId>
		  <artifactId>spring-cloud-starter-config</artifactId>
		</dependency>

2.修改启动类
去掉了config-server所使用的注解 @EnableConfigServer

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

3.修改全局配置文件 bootstrap.yml
因为配置了配置中心,配置文件从配置中心读取,不能再使用applocation.properties/yml,配置项目名,端口号注册中心等 .
必须在本地配置,所以这里使用优先级比application.properties/yml高的bootstrap.properties/yml文件。

spring:
  application:
    name: config-client
  cloud:
    config:
      discovery:
        service-id: config-server-Git    #config-server的服务名
        enabled: true    #开关
      profile: dev    #使用什么环境 test/dev/prod/default
      label: master    #git标签
        

server:
  port: 9091   #服务启动端口

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/
bootstrap与application的区别

在这里插入图片描述

4.编写一个controller ,去访问码云中的配置文件config-client-dev.properties
获取哪个配置文件根据 bootstrap.yml配置
通过@value注解+el表达式获取相关配置文件的具体的值

@Controller
public class showMsgController {
	
	@Value("${E-Book}")
	private String msg;
	
	@RequestMapping("showMsg")
	@ResponseBody
	public String showMsg() {
		
		return msg;
	}
}

测试结果
码云中在这里插入图片描述

浏览器中,注册中心截图省略
在这里插入图片描述

三、在 git 端修改配置后,在不重启服务中如何让客户端生效

在这里插入图片描述
当我们修改git端配置文件是需要重新启动项目才能重新加载配置文件。当然这样在实际生产中是不好。
在config-server中,每一次client请求时都会去git端同步版本,所以不需要从重启server端,只需要重启client端。
我们通过actuator中的/refresh完成client的重启操作。

1.修改配置中心Client端pom文件 (被同步数据的一端)

添加actuator的坐标

	<dependencies>
		<!-- devtools,热部署刷新工具 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<!-- 表示依赖不向下传递 -->
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- Eureka注册中心 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<!-- 网关服务 -->
		<dependency>
		  <groupId>org.springframework.cloud</groupId>
		  <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>
		<!-- 配置中心client -->
		<dependency>
		  <groupId>org.springframework.cloud</groupId>
		  <artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		
		
		<!-- actuator监控,在此处是帮助项目刷新配置中心修改的文件 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
	</dependencies>

2.修改其全局配置文件 bootbootstrap.yml

spring:
  application:
    name: config-client
  cloud:
    config:
      discovery:
        service-id: config-server-Git    #config-server的服务名
        enabled: true    #开关
      profile: dev    #使用什么环境 test/dev/prod/default
      label: master    #git标签
        

server:
  port: 9091

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

management:
# 2.0之前需要关闭防护
  #security:
   # enable: false
  endpoints:
    web:
      exposure:
        include: refresh

3.启动类

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

4.控制层
在springioc容器中,bean为单例模式/原型模式,
其值配注入后不会改变,刷新后也不会变化,需要@RefreshScope注解刷新属性

/**
 *在springioc容器中,bean为单例模式,其值配注入后不会改变,刷新后也不会变化,需要@RefreshScope注解刷新属性
 * @author chy
 *
 */
@Controller
@RefreshScope
public class showMsgController {
	
	@Value("${E-Book}")
	private String msg;
	
	@RequestMapping("showMsg")
	@ResponseBody
	public String showMsg() {
		
		return msg;
	}
}

5.启动server、启动client,修改git端数据使其数据改变,
例如修改上面代码中msg引用的值
在这里插入图片描述

cmd命令刷新git上的配置文件: curl -X POST http://localhost:服务的端口号/actuator/refresh

6.进入Windows命令行 , 使用 curl -X POST http://localhost:服务的端口号/actuator/refresh 刷新client
在刷新之前,可以先清除配置中心客户端的控制台 ,待输出如下数据说明刷新/重启数据完毕

在这里插入图片描述
在这里插入图片描述
7. 注意

  1. /refresh请求必须post方式,可以通过java程序发送post请求(HTTPClient工具类),也可以通过命令行curl发送。
  2. 对于@value注入的属性不能通过刷新重新加载,需要在该类上添加@RefreshScope注解。
  3. 2.0版本以前需要设置management.security.enabled=false ,2.0版本以后需要在配置中放开refresh

测试结果
在这里插入图片描述

四、 安全与加密

对于一些配置文件中的内容不宜明文显示,需要进行加密处理

  1. 对称加密介绍
    对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。

  2. 检查加密环境 http://127.0.0.1:配置中心服务端端口号/encrypt/status

    检查结果:
    出现下列结果需要为加密服务安装密钥。

      {"description":"No key was installed for encryption service","status":"NO_KEY"}2.0版本以前)
      {"description":"The encryption algorithm is not strong enough","status":"INVALID"}2.0版本以后)
    
  3. 设置加密环境
    步骤
    1.设置秘钥 KEY
    (必须在bootstrap.properties/yml文件中

    encrypt:
      key: chy  #配置加密环境的秘钥
    

    2.未配置 JCE
    http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
    下载解压后,把 jar 文件上传到需要安装 jce 机器上 JDK 或 JRE 的 security 目录下,覆盖源文件 即可。
    JDK:将两个 jar 文件放到%JDK_HOME%\jre\lib\security 下
    JRE:将两个 jar 文件放到%JRE_HOME%\lib\security 下

    3.spring cloud bug
    Dalston.SR4、Dalston.SR3、Dalston.SR2 版本不能对配置文件加密,若需要调整到 Dalston.SR1
    https://github.com/spring-cloud/spring-cloud-config/issues/767

    如果使用官网生成的2.17版本的SpringBoot项目,则无需修改第3步,pom文件如下

    <!-- SpringBoot配套的运行环境,一定要加上,不加会报错!!! -->
    	<properties>
    		<java.version>1.8</java.version>
    		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
    		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
    	</properties>
    
    <dependencyManagement>
    <dependencies>
    		<dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-dependencies</artifactId>
    			<version>${spring-cloud.version}</version>
    			<type>pom</type>
    			<scope>import</scope>
    		</dependency>
    	</dependencies>
    </dependencyManagement>
    
  4. 设置后检查设置结果
    在这里插入图片描述

  5. 加密演示
    加密(post 请求):http://ip:port/encrypt
    解密(post 请求):http://ip:port/decrypt
    通过Postman工具发送post请求

使用对称加密算法 ,实现敏感数据加密

1.创建配置中心服务端

主要添加的坐标

<!-- 配置中心server -->
		<dependency>
	      <groupId>org.springframework.cloud</groupId>
	      <artifactId>spring-cloud-config-server</artifactId>
	    </dependency>

配置文件 bootstrap.yml

spring:
  application:
    name: config-server-encryption-sym 
  cloud:
    config:
      server:
        git:    #Git 配置 
          uri: https://gitee.com/TimePause/SpringCloudConfig    #码云/git仓库地址
          username: 账号
          password: 密码
          skip-ssl-validation: true #解决Cannot clone or checkout repository 的问题
          
server:
  port: 9999

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

encrypt:
  key: chy  #配置加密环境的秘钥
2.使用HTTPClient向数据加密的服务中心配置发送命令,对数据进行加密

环境搭建

  1. 创建SpringCloud项目,修改pom文件

    <parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.1.7.RELEASE</version>
    	</parent>
    
    <!-- SpringBoot配套的运行环境,一定要加上,不加会报错!!! -->
    	<properties>
    		<java.version>1.8</java.version>
    		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
    		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
    	</properties>
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.apache.httpcomponents</groupId>
    			<artifactId>httpclient</artifactId>
    		</dependency>
    		<!-- log -->
    		<dependency>
    			<groupId>commons-logging</groupId>
    			<artifactId>commons-logging</artifactId>
    			<version>1.2</version>
    		</dependency>
    	</dependencies>
    
    	<dependencyManagement>
    		<dependencies>
    			<dependency>
    				<groupId>org.springframework.cloud</groupId>
    				<artifactId>spring-cloud-dependencies</artifactId>
    				<version>${spring-cloud.version}</version>
    				<type>pom</type>
    				<scope>import</scope>
    			</dependency>
    		</dependencies>
    	</dependencyManagement>
    
  2. 创建HTTPClient工具类,向其中发送需要加密的信息

    数据加密的服务中心配置发送请求
    a. 例如发送一个需要加密字符串 “root”
    返回一个加密的字符串 “baa42d01c077be2d26c7511d97845cf341427e7e9aefb726e941df7866816128”
    b. 然后重新发送解密字符串 “baa42d01c077be2d26c7511d97845cf341427e7e9aefb726e941df7866816128”
    验证是否返回root

    import java.io.IOException;
    import java.net.URI;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.http.NameValuePair;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.client.utils.URIBuilder;
    import org.apache.http.entity.ContentType;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.util.EntityUtils;
    
    public class HttpClientUtil {
    
    	public static String doGet(String url, Map<String, String> param) {
    
    		// 创建Httpclient对象
    		CloseableHttpClient httpclient = HttpClients.createDefault();
    
    		String resultString = "";
    		CloseableHttpResponse response = null;
    		try {
    			// 创建uri
    			URIBuilder builder = new URIBuilder(url);
    			if (param != null) {
    				for (String key : param.keySet()) {
    					builder.addParameter(key, param.get(key));
    				}
    			}
    			URI uri = builder.build();
    
    			// 创建http GET请求
    			HttpGet httpGet = new HttpGet(uri);
    
    			// 执行请求
    			response = httpclient.execute(httpGet);
    			// 判断返回状态是否为200
    			if (response.getStatusLine().getStatusCode() == 200) {
    				resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				if (response != null) {
    					response.close();
    				}
    				httpclient.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		return resultString;
    	}
    
    	public static String doGet(String url) {
    		return doGet(url, null);
    	}
    
    	public static String doPost(String url, Map<String, String> param) {
    		// 创建Httpclient对象
    		CloseableHttpClient httpClient = HttpClients.createDefault();
    		CloseableHttpResponse response = null;
    		String resultString = "";
    		try {
    			// 创建Http Post请求
    			HttpPost httpPost = new HttpPost(url);
    			// 创建参数列表
    			if (param != null) {
    				List<NameValuePair> paramList = new ArrayList<>();
    				for (String key : param.keySet()) {
    					paramList.add(new BasicNameValuePair(key, param.get(key)));
    				}
    				// 模拟表单
    				UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"utf-8");
    				httpPost.setEntity(entity);
    			}
    			// 执行http请求
    			response = httpClient.execute(httpPost);
    			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				response.close();
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    
    		return resultString;
    	}
    
    	public static String doPost(String url) {
    		return doPost(url, null);
    	}
    	
    	public static String doPostJson(String url, String json) {
    		// 创建Httpclient对象
    		CloseableHttpClient httpClient = HttpClients.createDefault();
    		CloseableHttpResponse response = null;
    		String resultString = "";
    		try {
    			// 创建Http Post请求
    			HttpPost httpPost = new HttpPost(url);
    			// 创建请求内容
    			StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
    			httpPost.setEntity(entity);
    			// 执行http请求
    			response = httpClient.execute(httpPost);
    			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				response.close();
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    
    		return resultString;
    	}
    	
    	public static void main(String[] args) {
    		//刷新服务请求
    		//String url ="http://localhost:9091/actuator/refresh";
    		//加密请求
    		//String url ="http://localhost:9999/encrypt";//baa42d01c077be2d26c7511d97845cf341427e7e9aefb726e941df7866816128
    		//解密请求
    		String url ="http://localhost:9999/decrypt";
    		
    		//该url必须要使用dopost方式来发送
    		//加密
    		//String doPostJson = HttpClientUtil.doPostJson(url, "root");
    	    //解密
    		String doPostJson = HttpClientUtil.doPostJson(url, "baa42d01c077be2d26c7511d97845cf341427e7e9aefb726e941df7866816128");
    	    System.out.println(doPostJson);
    	}
    }
    		
    
3.配置中心客户端(E-Book-Product-Provider)

主需要额外添加的坐标

<!-- 配置中心client -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>

bootstrap.yml
保留的参数 应用名,端口号,不重启服务刷新配置文件的配置 , 注册中心配置

spring:
  application:
    name: config-E-Book-Product-Provider
  #配置中心服务端的连接信息  
  cloud:
    config:
      discovery:
        service-id: config-server-encryption-sym    #configserver的服务名
        enabled: true    #开关
      label: master    #git标签
server:
  port: 8001
management:
  endpoints:
    web:
      exposure:
        include: refresh
eureka:
  instance:
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

注意:
配置refresh属性后并且添加actuator的坐标,以后在码云中更改配置文件后在服务中生效
只需要在命令行输入 curl -X POST http://localhost:8001这个服务端口号/actuator/refresh
例如: curl -X POST http://localhost:8001/actuator/refresh

4.需要将数据库的相关配置/下面代码上传至配置中心(码云/git)

在比较长的字符串的前后最好加上单引号,不然可能会报错,
这里推荐url,加密后的用户名和密码的前后需要加上单引号
注册中心的文件不能放到配置中心/码云上 ,这是我们区分是否将配置文件上传的一个依据

spring:
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    url:  'jdbc:mysql://localhost:3306/book-product?useUnicode=true&characterEncoding=gbk&useJDBCCompliantTimezoneShift=true&serverTimezone=UTC'
    username: '{cipher}baa42d01c077be2d26c7511d97845cf341427e7e9aefb726e941df7866816128'
    password: '{cipher}baa42d01c077be2d26c7511d97845cf341427e7e9aefb726e941df7866816128'
    type: com.alibaba.druid.pool.DruidDataSource

  
server:
  compression:   #springboot的gzip配置
    enabled: true   #是否启用压缩  
    mime-types:    #配置压缩支持的 MIME TYPE
    - application/json,application/ xml,text/html,text/xml,text/plain
    
mybatis:
  type-aliases-package: ah.szxy.product.pojo
  mapper-locations:
  - classpath:ah/szxy/product/mapper/*.xml 

在这里插入图片描述

5.通过配置中心服务端访问码云上的配置文件,查看是否显示解密后的数据

在这里插入图片描述

6.出现上图后 ,启动被提供加密服务(E-Book-Product-Provider) ,访问相关的方法,查看联网的配置是否可用

在这里插入图片描述

注意 :
a.将需要加密的数据进行通过config-server加密(每次加密结果不一样,但都能解密出相同的结果)
b.在密码前需要加上{cipher},这样config-server才能解密出明文密码。

使用非对称加密算法 ,实现敏感数据加密

非对称加密介绍
在这里插入图片描述

Java-keytool 使用说明

  1. Keytool 介绍
    Keytool 是一个 Java 数据证书的管理工具 。 它的作用是帮助配置服务实现64位非对称秘钥的生成
    Keytool 将密钥(key)和证书(certificates)存在一个称为 keystore 的文件中。
    keystore 文件,包含两种数据:密钥实体(Key entity)-密钥(secret key)或者是私钥和配对公钥(采用非对称加密)可信任的证书实体(trusted certificate entries)-只包含公钥.
    位于JAVA_HOME/jdk/bin/keytool.exe

  2. 使用keytool创建证书
    使用有管理员权限的命令行,在keytool.exe目录 shift+鼠标右键 打开power shell(或使用cmd跳转到该目录)
    后执行 keytool -genkeypair -alias "test1" -keyalg "RSA" -keystore "test.keystore"
    keytool -genkey -alias andro eyalg RSA -validity 30000 -keystore

    在这里插入图片描述

    在这里插入图片描述

    生成的test.keystire文件位于JAVA_HOME/jdk/bin/。

    在这里插入图片描述

使用非对称加密算法实现配置文件加密与解密
前提 : 需要有keytool创建的证书

1.配置中心服务端

pom文件如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.7.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>ah.szxy.springcloud</groupId>
	<version>0.0.1-SNAPSHOT</version>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- 配置中心server -->
		<dependency>
	      <groupId>org.springframework.cloud</groupId>
	      <artifactId>spring-cloud-config-server</artifactId>
	    </dependency>
		
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</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>

	<name>Config-Server-Encryption</name>
	<artifactId>Config-Server-Encryption</artifactId>
</project>

修改配置文件 bootstrap.yml

spring:
  application:
    name: config-server-rsa-sym
  cloud:
    config:
      server:
        git:    #Git 配置 
          uri: https://gitee.com/TimePause/SpringCloudConfig
          username: 码云账号
          password: 码云密码
          skip-ssl-validation: true #解决Cannot clone or checkout repository 的问题
          
server:
  port: 9999

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/
      
#使用非对称加密
#keytool -genkeypair -alias "config-info" -keyalg "RSA" -keystore "encrypt-info.keystore"
encrypt:
  key-store:
  # keystore 文件的路径 
    location: classpath:encrypt-info.keystore
    # alias 指定密钥对的别名,该别名是公开的; 
    alias: config-info
    # storepass 密钥仓库 
    password: caohaiyang
    # keypass 用来保护所生成密钥对中的私钥 
    secret: caohaiyang   

将2.2生成好的加密文件放到src目录下

在这里插入图片描述
创建启动类,然后启动

@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

2.使用对称加密使用到的HTTPClient工具类向生成秘钥的项目发送请求

对相关数据进行加密(如数据库的用户名和密码)
得到的是一个64位的字符串

3.创使用非对称加密的项目( config-E-Book-Product-Provider-RSA )

复制对称加密使用的项目,修改其全局配置文件 bootstrap

spring:
  application:
    name: config-E-Book-Product-Provider-RSA
  #配置中心服务端的连接信息  
  cloud:
    config:
      discovery:
        service-id: config-server-rsa-sym    #configs-erver的服务名
        enabled: true    #开关
      label: master    #git标签
server:
  port: 8011
management:
  endpoints:
    web:
      exposure:
        include: refresh
eureka:
  instance:
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/
4.在码云上创建 config-E-Book-Product-Provider-RSA.yml文件 ,修改其内容

文件名称是依据 bootstrap中服务的应用名而起的

在这里插入图片描述

5.通过生成秘钥的服务中心访问创建好的配置文件

这里可以看到密码已经被解密
在这里插入图片描述
注意:本次模拟主要是对数据库的用户名和密码进行的加密

6.访问被加密的项目,发现可以正常运行

在这里插入图片描述

配置中心的用户安全认证

以非对称加密为例 ,对称加密安全认证同上

配置中心服务端

添加security坐标

<!-- 安全认证 -->		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>	
<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- 配置中心server -->
		<dependency>
	      <groupId>org.springframework.cloud</groupId>
	      <artifactId>spring-cloud-config-server</artifactId>
	    </dependency>
		<!-- 注册中心 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>	

修改全局配置文件

spring:
  application:
    name: config-server-rsa-sym-security
  cloud:
    config:
      server:
        git:    #Git 配置 
          uri: https://gitee.com/TimePause/SpringCloudConfig
          username: 码云账号
          password: 码云密码
          skip-ssl-validation: true #解决Cannot clone or checkout repository 的问题
  # 安全认证
  #开启基于 http basic 的安全认证
  security:
    user:  
      name: root
      password: root    
          
          
server:
  port: 9999

eureka:
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/
      
#使用非对称加密
#keytool -genkeypair -alias "config-info" -keyalg "RSA" -keystore "encrypt-info.keystore"
encrypt:
  key-store:
  # keystore 文件的路径 
    location: classpath:encrypt-info.keystore
    # alias 指定密钥对的别名,该别名是公开的; 
    alias: config-info
    # storepass 密钥仓库 
    password: caohaiyang
    # keypass 用来保护所生成密钥对中的私钥 
    secret: caohaiyang      

再次通过[配置中心服务端访问码云上的配置文件时,需要输入配置文件设置的用户名和密码才能访问
在这里插入图片描述

配置中心客户端

pom文件无需修改,但是如果直接访问,会出现如下错误:在这里插入图片描述
解决方式:
在全局配置文件中添加安全认证的用户名密码
在这里插入图片描述

spring:
  application:
    name: config-E-Book-Product-Provider-RSA
  #配置中心服务端的连接信息  
  cloud:
    config:
      discovery:
        service-id: config-server-rsa-sym-security    #configs-erver的服务名
        enabled: true    #开关
      label: master    #git标签
      username: root
      password: root
      
server:
  port: 8011
  
management:
  endpoints:
    web:
      exposure:
        include: refresh
eureka:
  instance:
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

测试结果
在这里插入图片描述

  • 8
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时间静止不是简史

感谢你的肯定, 我将继续努力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值