Feign注解源码

EnableFeignClients注解背后加载流程

  • @EnableFeignClients的@Import(FeignClientsRegistrar.class)实现注册
  • class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, 
    EnvironmentAware
  • 注册类

      @Override
      public void registerBeanDefinitions(AnnotationMetadata metadata,
              BeanDefinitionRegistry registry) {
         //注册默认配置
          registerDefaultConfiguration(metadata, registry);
          registerFeignClients(metadata, registry);
      }

    1.1 registerDefaultConfiguration

          private void registerDefaultConfiguration(AnnotationMetadata metadata,
              BeanDefinitionRegistry registry) {
          //获取@EnableFeignClients注解中声明的变量值
          Map<String, Object> defaultAttrs = metadata
                  .getAnnotationAttributes(EnableFeignClients.class.getName(), true);
    
          if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
              String name;
            //该方法是否继承任何类
              if (metadata.hasEnclosingClass()) {
                  name = "default." + metadata.getEnclosingClassName();
              }
              else {
                //name = "default" + 包名 + 启动类
                  name = "default." + metadata.getClassName();
              }
             //构造上下文中需要用到的Bean信息并注册
              registerClientConfiguration(registry, name,
                      defaultAttrs.get("defaultConfiguration"));
          }
      }
          private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
              Object configuration) {
                    //构造FeignClientSpecification类
          BeanDefinitionBuilder builder = BeanDefinitionBuilder
                  .genericBeanDefinition(FeignClientSpecification.class);
                  //把main函数类名传入
          builder.addConstructorArgValue(name);
                  //传入配置项
           builder.addConstructorArgValue(configuration);
                  //通过registerBeanDefinition注册Bean
          registry.registerBeanDefinition(
                  name + "." + FeignClientSpecification.class.getSimpleName(),
                  builder.getBeanDefinition());
      }

Spring中Bean加载模式的扩展点

Feign构造上下文对象(FeignContext)的过程

整合Spring Cloud Alibaba

maven pom增加依赖
f90b8d8132ab3243169f752514e83e6e.png

<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>

整合Spring Cloud Alibaba

wiki版本说明
根据SpringCloud版本在dependencyManagement添加依赖
Greenwich版本时Pom依赖:

<dependencyManagement>
        <!--整合Spring cloud-->
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <!--整合spring cloud alibaba-->
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>

    </dependencyManagement>

整合后使用对应组件依赖无需填写版本号,而是由dependencyManagement内的文件控制

服务提供者与服务消费者

名词定义
服务提供者/服务端server服务的被调用方(为其他微服务提供接口的微服务)
服务消费者/客户端client服务的调用方(调用其他微服务接口的微服务)

一般成对出现

服务发现原理

3ab1951d082216bdba1635dcd0f9c956.png

  • 服务发现组件挂了,本地缓存继续调用
  • 每次调用都需要请求服务发现组件?用本地缓存通信
    0dc2442d8dc8c40d56e70e43cb5e2215.png

什么是Nacos

  • 官方文档
  • 一个服务发现组件、配置服务器
  • 管理微服务的配置
  • 服务A如何找道服务B的解决方案98dee211e3b309622386c1c9041e6c60.png
  • 微服务需集成nacos client

搭建Nacos Server

  • 下载Nacos
  • 89541dea79a9c372bd55c7d2c28114e8.png
  • 启动后根据命令行提示nacos is starting,you can check the /Users/panshenghao/Downloads/nacos/logs/start.out
  • 查看start.out文件可以找到登录网页
  •        ,--.
         ,--.'|
     ,--,:  : |                                           Nacos 1.1.4
    ,`--.'`|  ' :                       ,---.               Running in stand alone mode, All function modules
    |   :  :  | |                      '   ,'\   .--.--.    Port: 8848
    :   |   \ | :  ,--.--.     ,---.  /   /   | /  /    '   Pid: 96058
    |   : '  '; | /       \   /     \.   ; ,. :|  :  /`./   Console: http://192.168.29.192:8848/nacos/index.html
    '   ' ;.    ;.--.  .-. | /    / ''   | |: :|  :  ;_
    |   | | \   | \__\/: . ..    ' / '   | .; : \  \    `.      https://nacos.io
    '   : |  ; .' ," .--.; |'   ; :__|   :    |  `----.   \
    |   | '`--'  /  /  ,.  |'   | '.'|\   \  /  /  /`--'  /
    '   : |     ;  :   .'   \   :    : `----'  '--'.     /
    ;   |.'     |  ,     .-./\   \  /            `--'---'
    '---'        `--`---'     `----'

应用注册至Nacos

  • pom加依赖、配置整合SpringCloudAlibaba后不用加版本号

    <dependency>
              <groupId>com.alibaba.cloud</groupId>
              <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
          </dependency>
  • 注解 新版本无需注解,早期需要@EnableDiscoveryClient
  • 配置application.yml

    spring:
    cloud:
      nacos:
        discovery:
          #指定nacos server的地址
          server-addr: localhost:8848
    application:
      #服务名称尽量用-,不要用_,不要用特殊字符
      name: user-center
    
  • No service to register for nacos client application.name未配置(服务名称未配置)
  • 配置完毕后启动微服务
    2c5470450d40059a205bc2b69a118347.png
  • 出现服务则成功

@ImportResource And @PropertyResource and ClassPath

@ImportResource

  • 作用:在主配置类上引入,只能引入Spring配置文件 .xml,管理配置bean
  • 引入.properties时报错样例:
    5759dbece00ecce87d84c56265ac1597.png
  • 前言中不允许有内容:可能是由于编码格式非UTF-8原因
    此处是properties文件非xml文档声明导致解析报错:
    <?xml version="1.0" encoding="utf-8" standalone="yes" ?>

@PropertyResource

  • 作用:加载非全局配置文件(.properties),

classpath

  • 代表target内classes路径下文件

@Component

代码样例

9509f3f9a88b711c2995a7fd2bd7550c.png

定义

@Component 标明哪个类被扫描进入Spring IoC容器
配置的user作为Bean名称,否则默认类名且令第一个字母为小写

@Value 指定具体值,使Spring IoC给予对应属性注入对应值

@ComponentScan

定义需要扫描的路径并将标识需要装配( @Component、@Controller、@Service、@Repository)的类自动装配到Bean容器中
在没有定义路径的情况下,默认扫描当前包和其子包下的路径
可通过basePackageClasses定义扫描类

  • includeFilters 定义满足过滤器(Filter)条件的Bean才去扫描
  • excludeFilters 定义排除过滤器条件的Bean,都需要@Filter去定义
    以下三种方式扫描到User类
@ComponentScan("com.springboot.chapter3.*")
@ComponentScan(basePackages = {"com.springboot.chapter3.pojo"})
@ComponentScan(basePackageClasses = {User.class})
excludeFilters Example:
@ComponentScan(basePackages = "com.springboot.chapter3.*", excludeFilters = {@Filter(classes = {Service.class})})