Nacos配置管理Feign远程调用Gateway服务网关

1.统一配置管理

1.统一配置管理流程

1.引入Nacos的配置管理客户端依赖
    <dependency>    
        <groupId>com.alibaba.cloud</groupId>    
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>


2.在userservice中的resource目录添加一个bootstrap.yml文件,这个文件是引导文件,优先级高于application.yml
    spring:  
        application:    
            name: userservice # 服务名称  
        profiles:    
            active: dev #开发环境,这里是dev   
        cloud:    
            nacos:      
                server-addr: localhost:8848 # Nacos地址      
                config:        
                    file-extension: yaml # 文件后缀名


3.在nacos中编写配置文件

4.在user-service中将pattern.dateformat这个属性注入到UserController中做测试
         @Value("${pattern.dateformat}")
         private String dateformat;

总结:1.在微服务的pom文件中添加nacos的config依赖。

2.创建bootstrap.yml,配置nacos地址,以及配置在nacos中的配置文件名。

3.在nacos中添加配置文件。

1.配置自动刷新:

配置文件变更后,微服务无需重启就可以感知

方式一:

1.在@Value注入的变量所在类上添加注解@RefreshScope
@RefreshScope
public class UserController {
    
    @Value("${pattern.dateformat}")
   private String dateformat;

方式二:

2.使用@ConfigurationProperties注解

        1.创建一个类用于接收属性。
@Data
@Component
/*
* 热更新2
* */
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    private String dateformat;
    private String envShareValue;
}


        2.在controller中注入调用

    @Autowired
    private PatternProperties patternProperties;


    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()+"==="+patternProperties.getEnvShareValue()));

总结:Nacos配置更改后实现热更新的方法有两个:

1.使用@Value注解注入,结合@RefreshScope来刷新。

2.通过@ConfigurationPreperties注入,自动刷新。

注意

1.不是所有的配置都适合放在配置中心,维护起来比较麻烦

2.建议将一些关键参数,需要运行时调整的参数放到nacos配置中心,一般都是自定义配置。

2.多环境共享:

配置文件的格式:
格式1.[spring.application.name]-[spring.profiles.active].yaml
格式2.[spring.application.name].yaml
无论profile如何变化,[spring.application.name].yaml这个文件一定会加载,因此多环境共享配置可以写入这个文件

优先级:

总结

配置文件有两种格式:

1.[服务名]-[spring.profile.active].yaml,环境配置

2.[服务名].yaml,默认配置,多环境共享

优先级:

[服务名]-[环境].yaml >[服务名].yaml > 本地配置

3.nacos集群搭建

步骤:
1.搭建MySQL集群并初始化数据库表
2.下载解压nacos
3.修改集群配置(节点信息)、数据库配置
4.分别启动多个nacos节点
5.nginx反向代理

2.http客户端Feign

1.Feign替代RestTemplate

String url = " http://userservice/user/ "+ order.getUserId();User user = restTemplate.getForObject(url, User. class);
RestTemplate方式的代码可读性差,编程体验不统一
参数复杂URL难以维护

1.Feign的使用步骤:

1.引入依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2.在order-service的启动类添加注解开启Feign的功能:
/*
* 开启自动配置的开关
* */
@EnableFeignClients
public class OrderApplication {

3.编写Feign客户端接口:(主要是基于SpringMVC的注解来声明远程调用的信息)
@FeignClient("userservice")
public interface UserClient {

    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

4.用Feign客户端代替RestTemplate
@Service
public class OrderService {

    @Autowired
    private UserClient userClient;

    @Autowired
    private OrderMapper orderMapper;

    public Order queryOrderById(Long orderId){

        //查询订单
        Order order = orderMapper.findById(orderId);
        //用Feign远程调用
        User user = userClient.findById(order.getUserId());
        //封装user到Order
        order.setUser(user);
        //返回
        return order;
    }
}

order-service
@RestController
@RequestMapping("order")
public class OrderController {

   @Autowired
   private OrderService orderService;

    @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        // 根据id查询订单并返回
        return orderService.queryOrderById(orderId);
    }
}

user-service
 @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id,@RequestHeader(required = false,value = "Truth") String t) {
        System.out.println(t);
        return userService.queryById(id);
    }

总结:1.引入依赖

2.添加@EnableFerignClients注解

3.编写FeignClient接口

4.使用FeignClient中定义的方法代替RestTemplate

2.自定义配置

方式一:(全局生效)

feign:
  client:
    config:
      default:
        loggerLevel: FULL

方式二:(局部生效)

feign:
  client:
    config:
      userservice:
        loggerLevel: FULL

方式三:java代码方式需要先声明一个Bean

1.需要先声明一个Bean
    public class FeignClientConfiguration {

    @Bean
    public Logger.Level feignLogLevel(){
        return Logger.Level.NONE;
    }
}

    1.如果是全局配置,则把它放到@EnableFeignClients这个注解中:
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
/*
* 开启自动配置的开关
* clients:指定扫描包
* */
public class OrderApplication {

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

    2.如果是局部变量就放到@FeignClien这个注解中:
@FeignClient(value="userservice",configuration = FeignClientConfiguration.class)
public interface UserClient {

    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

总结:1.配置文件方式:

feign.client.config.XXX.loggerLevel:

XXX为default则代表全局

XXX是服务名称,则代表某个服务

2.java代码配置:

@EnableFeignClients:代表全局生效

@FeignClient:代表某个服务

3.Feign使用优化

Feign底层客户端实现
         URLConnection:默认实现,不支持连接池
         Apache HttpClient:支持连接池
         OKHttp:支持连接池
   如何优化?
1.使用支持连接池的连接
2.日志级别,最好是basic和none

Feign添加HttpClient连接:

1.引入依赖:
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>   
2.配置连接池:
feign:
  httpclient:
    enabled: true #开启feign对HttpClient的支持
    max-connections: 200 #最大连接数
    max-connections-per-route: 50  #每个路径的最大连接数

总结:1.日志尽量用basic

 2.使用HttpClient或OKHttp代替URLConnection

1.引用feign-httpClient依赖

2.配置文件开启httpClient功能,设置连接池参数

4.最佳实践

实现最佳实践方法二的步骤如下:
       1.首先创建一个module,命名为feign-api,然后引用feign的starter依赖
       2.将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中
       3.在order-service中引入feign-api的依赖
       4.修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包

                                 问题:当定义的FeignClient不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用。

解决

1.指定FeignClient所在包
@EnableFeignClients(basePackages = "cn.itcast.feign.clients",defaultConfiguration = FeignClientConfiguration.class)

2.指定FeignClient字节码
@EnableFeignClients(clients = UserClient.class,defaultConfiguration = FeignClientConfiguration.class)
/*
* 开启自动配置的开关
* clients:指定扫描包
* */
public class OrderApplication {

统一网关Gateway:

1.网关功能:
         1.身份认证和权限校验
         2.服务路由,负载均衡
         3.请求限流

Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。

gateway使用:

1.创建gateway模块,引入SpringCloudGateway的依赖和nacos的服务发现依赖
<!--服务发现依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--网关gateway依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>
2.编写路由配置以及nacos地址
server:
  port: 10010 #网关端口

spring:
  application:
    name: gateway #服务名称

  cloud:
    nacos:
      server-addr: localhost:80 #nacos地址

    gateway:
        routes:  #网关路由配置
        - id: user-service #路由id,自定义,只要唯一即可
#          uri: http://127.0.0.1:8081 #路由的目标地址(定死了)
          uri: lb://userservice #路由的目标地址,lb就是负载均衡,后面跟服务名
          predicates: #路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** #这个是按路径匹配,只要以/user/开头就符合要求。

总结:路由配置包括:

1.路由id:路由的唯一标示

2.路由目标uri:路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡

3.路由断言:判断路由的规则,符合则转发到路由目的地

4.路由过滤器:对请求或响应做处理

断言工厂:

过滤器工厂:

1.过滤器(只对当前请求生效)
routes:  #网关路由配置
        - id: user-service #路由id,自定义,只要唯一即可
#          uri: http://127.0.0.1:8081 #路由的目标地址(定死了)
          uri: lb://userservice #路由的目标地址,lb就是负载均衡,后面跟服务名
          predicates: #路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** #这个是按路径匹配,只要以/user/开头就符合要求。
          filters:
           - AddRequestHeader=Truth,Itcast is freaking awesome!

2.默认过滤器(对所有的路由都生效)
- id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**
      default-filters: #默认过滤器,会对所有路由都生效。
        - AddRequestHeader=Truth,Itcast is freaking awesome! #添加请求头

全局过滤器:

全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。
区别在于GatewayFilter通过配置定义,处理逻辑是固定的。而GlobalFilter的逻辑需要自己写代码实现。
定义方式是实现GlobalFilter接口。
//@Order(-1)//==Ordered
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
    /**
     * 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
     * @param exchange 请求上下文,里面可以获取Request,Response等信息
     * @param chain 用来把请求委托给下一个过滤器
     * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
     */
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){
        //1.获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String, String> queryParams = request.getQueryParams();
        //2.获取参数中的authorization参数
        String authorization = queryParams.getFirst("authorization");

        //3.判断参数值是否等于admin
        if (authorization .equals("admin")){
            //4.是,放行
            return chain.filter(exchange);
        }

        //5.否,拦截
//            5.1设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);//未登录
//            5.2拦截请求
        return exchange.getResponse().setComplete();
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

总结

全局过滤器的作用:

对所有路由都生效的过滤器,并且可以自定义处理逻辑

实现步骤:

1.实现GlobalFilter接口

2.添加@Order注解或实现Order接口

3.编写处理逻辑

1.每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
2.GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
3.路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
4.当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。

跨域问题:

跨域:域名不一致就是跨域,主要包括:
域名不同: www.taobao.comwww.taobao.orgwww.jd.commiaosha.jd.com
域名相同,端口不同:localhost: 8080和localhost8081
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决方案:CORS
网关处理跨域问题采用的同样是CORS方案,并且只需要简单配置即可实现:
gateway:
      globalcors: #全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        cors-configurations:
          '[/**]':
            allowedOrigins:  # 允许哪些网站的跨域请求
              - "http://localhost:8090"
              - "http://www.leyou.com"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" #允许在请求中携带的头信息
            allowCredentials: true #是否允许携带cookie
            maxAge: 360000 #这次跨域检测的有效期


版权声明:本文为qq_53063293原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。