1.统一配置管理
配置更改热更新

①在Nacos中添加配置信息:

②在弹出表单中填写配置信息:

2.配置获取的步骤如下

配置文件bootstrap.yml的优先级比application.yml优先级高。把nacos地址放入bootstrap.yml。
①在userservice中引入Nacos的配置管理客户端依赖:
- <dependency>
- <groupId>com.alibaba.cloudgroupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
- dependency>
②在userservice中的resource目录添加一个bootstrap.yml文件,这个文件是引导文件,优先级高于application.yml:
- spring:
- application:
- name: userservice # 服务名称
- profiles:
- active: dev # 环境
- cloud:
- nacos:
- server-addr: localhost:8848 # nacos地址
- config:
- file-extension: yaml # 文件后缀名
在微服务中添加bootstrap.yml,配置nacos地址、当前环境、服务名称、文件后缀名。这些决定了程序启动时去nacos读取哪个文件。
③在user-service中将pattern.dateformat这个属性注入到UserController中做测试

④访问http://localhost:8081/user/now获取时间对应格式,配置生效

3.配置自动更新
Nacos配置更新,无需重启微服务就可以配置更新。
方式一:在@Value注入的变量所在类上添加注解@RefreshScope

方式二:
使用@ConfigurationProperties注解
①创建一个配置类PatternProperties
- @Component
- @Data
- @ConfigurationProperties(prefix = "pattern") // 跟配置文件的顶级名一致
- public class PatternProperties {
- private String dateformat;
- }
②在需要用的controller进行注入
总结:
注意事项:
4.多服务共享配置
启动的时候从nacos读取多个配置文件优先级

userservice-dev.yaml>userservice.yaml>application.yml
无论profile如何变化,[spring.application.name].yaml这个文件一定会加载,因此多环境共享配置可以写入这个文件。
总结:

1.RestTemplate方式存在的问题
RestTemplate远程调用的代码
String url = "http://userservice/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
①代码可读性差,编程体验不统一
②参数复杂时URL难以维护
2.定义和使用Feign客户端
①在orderservice导入依赖
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-openfeignartifactId>
- dependency>
②在启动类添加注解开启Feign功能@EnableFeignClients

③编写Feign客户端接口
- @FeignClient("userservice") //提供者名
- public interface UserClient {
- @GetMapping("/user/{id}")
- User findById(@PathVariable("id") Long id);
- }
④使用Feign客户端代替RestTemplate

总结:
3.配置Feign日志的两种方式
feign.Logger.Level 修改日志级别 包含四种不同的级别:NONE、BASIC、HEADERS、FULL
方式一
配置文件方式
①全局生效

②局部生效

方式二
①声明一个Bean
- public class FeignClientConfiguration {
- @Bean
- public Logger.Level feignLogLevel(){
- return Logger.Level.BASIC;
- }
- }
②全局配置,则把它放到@EnableFeignClients这个注解中
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
③局部配置,则把它放到@FeignClient这个注解
@FeignClient(value="userservice",configuration = FeignClientConfiguration.class)
总结
方式一是配置文件,feign.client.config.xxx.loggerLevel
方式二是java代码配置Logger.Level这个Bean
4.Feign性能优化
①Feign连接池的设置
引入httpClient依赖

配置连接池

优化总结
引入feign-httpClient依赖
配置文件开启httpClient功能,设置连接池参数
5.Feign的最佳实践
方式一(继承):给消费者的FeignClient和提供者controller定义统一的父接口。然后实现接口

缺点
方式二(抽取):将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用

6.抽取FeignClient




注意:
当定义的FeignClient不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用。有两种方式解决:
方式一:指定FeignClient所在包
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
方式二:指定FeignClient字节码
@EnableFeignClients(clients = {UserClient.class})
1.为什么需要网关
①对用户请求做身份验证、权限校验。
②将用户请求路由到微服务,实现负载均衡
③用户请求做限流

2.网关技术的实现
SpringCloud实现网关的方式
①gateway
②zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
3.搭建网关服务
①创建新的module,引入SpringCloudGateway的依赖和nacos的服务发现依赖:
- <dependency>
- <groupId>com.alibaba.cloudgroupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-gatewayartifactId>
- dependency>
②编写路由配置及nacos地址
- server:
- port: 10010
- spring:
- application:
- name: gateway
- cloud:
- nacos:
- server-addr: localhost:8848 #nacos地址
- gateway:
- routes:
- - id: user-service #路由标识,唯一
- uri: lb://userservice # 路由的目标地址
- predicates: # 判断请求的规则
- - Path=/user/** # 路径的规则
- - id: order-service #路由标识,唯一
- uri: lb://orderservice # 路由的目标地址
- predicates: # 判断请求的规则
- - Path=/order/** # 路径的规则
③测试 http://localhost:10010/order/101

端口请求访问的是网关,基于路由规则判断,拉取服务列表,进行负载均衡发送请求。
总结:

4.路由断言工厂 Route Predicate Factory

问题
读取用户定义的断言条件,对请求做出判断
路径是以/user开头的就认为是符合的
5.过滤工厂GatewayFilterFactory
GatewayFilter是网关提供的一种过滤器,对进入网关的请求和微服务的返回的响应做处理

过滤工厂

案例:所有进入userservice的请求添加一个请求头
请求头:Truth=itcast is freaking awesome!
①在gateway的配置文件application.yml添加过滤配置

②在user-service的UserController,获取请求头参数
- @GetMapping("/prop")
- public String prop(@RequestHeader(value = "Truth", required = false) String truth) {
- return truth;
- }
③访问http://localhost:10010/user/prop
注意:
所有的路由都生效的过滤器

总结
对路由的请求或响应做加工处理,比如添加请求头
配置在路由下的过滤器只对当前路由的请求生效
对所有路由都生效的过滤器
6.全部过滤器
实现GlobalFilter接口
- public interface GlobalFilter {
- Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain); - }
ServerWebExchange:请求上下文,获取request,response信息
GatewayFilterChain:把请求交给下一个过滤器
案例:定义全局过滤器,拦截并判断用户身份
判断请求的参数是否满足下面条件:
如果同时满足则放行,否则拦截
步骤:
①在gateway编写自定义全局过滤器
- @Order(-1)
- @Component
- public class AuthorizeFilter implements GlobalFilter {
- @Override
- public Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain) { - // 1.获取请求参数
- MultiValueMap
params = exchange.getRequest().getQueryParams(); - // 2.获取参数的authorization
- String auth = params.getFirst("authorization");
- // 3.判断是否是admin
- if ("admin".equals(auth)){
- // 放行
- return chain.filter(exchange);
- }
-
- //4.不放行就禁止
- exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
- // 5.结束处理
- return exchange.getResponse().setComplete();
- }
- }
②发起请求

总结

7.过滤器执行顺序
请求进入网关会碰到三类过滤器:DefaultFilter、当前路由的过滤器、GlobalFilter

①每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
②当order值一样时,顺序是defaultFilter最先,然后是局部的路由过滤器,最后是全局过滤器
8.跨域问题处理
在实际项目中,前后端分成两个不同的项目,各自部署在不同的域名下,这也就会遇到跨域问题了。浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决方案:CORS
