Feign原理_feign基于什么协议

Feign原理_feign基于什么协议一、feign测试代码1.服务接口上标注@FeignClient@FeignClient(“order”)publicinterfaceOrderServiceFeign{@GetMapping(“/getOrder”)StringgetOrder();}2.调用方可以直接注入然后直接调用访问@RestController@RequestMapping(“/feign”)publicclassFeignTestController{@Autow

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

一、feign测试代码

1.服务接口上标注@FeignClient

@FeignClient("order")
public interface OrderServiceFeign { 
   
    @GetMapping("/getOrder")
    String getOrder();
}

2.调用方可以直接注入然后直接调用访问

@RestController
@RequestMapping("/feign")
public class FeignTestController { 
   

    @Autowired
    private OrderServiceFeign orderServiceFeign;
    
    @GetMapping("/order")
    public String getOrder() { 
   
        return orderServiceFeign.getOrder();
    }
}

3.在调用方的启动类上加上一个启动注解@EnableFeignClients

@SpringBootApplication
@EnableFeignClients
public class UserServiceApplication { 
   
    public static void main(String[] args) { 
   
        SpringApplication.run(UserServiceApplication.class, args);
    }
}
二、寻找入口

springcloud组件基本都是启动的注解,也就是@EnableFeignClients

1.@EnableFeignClients干了什么?
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients { 
   

我们看到Import注解里面有个FeignClientsRegistrar类,在spring中看到以Registrar结尾的类,就会想到spring的bean的动态装备,一个是selecter,一个是registrar.

简单介绍下registrar
比如我们要将类RegistrarBean 装在的spring 装载到spring容器

public class RegistrarBean { 
   
}

定义一个类实现ImportBeanDefinitionRegistrar 接口,实现registerBeanDefinitions方法,然后通过registry的registerBeanDefinition可以注册一个实例到spring当中

public class SpringRegistrarTest implements ImportBeanDefinitionRegistrar { 
   
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 
   
        BeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName(RegistrarBean.class.getName());
        registry.registerBeanDefinition("registrarBean",beanDefinition);
    }
}

定义一个自定义注解,用Import注解导入我们上面写的SpringRegistrarTest 类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(SpringRegistrarTest.class)
public @interface EnableRegistrar { 
   
}

将我们写的注解配置到启动类上

@SpringBootApplication
@EnableFeignClients
@EnableRegistrar
public class UserServiceApplication { 
   

    public static void main(String[] args) { 
   
        ConfigurableApplicationContext applicationContext = SpringApplication.run(UserServiceApplication.class, args);
        Object registrarBean = applicationContext.getBean("registrarBean");
        System.out.println(registrarBean);
    }
}

我们在返回的context对象去获取我们去注册的bean,是可以拿到的
在这里插入图片描述

我们接着看FeignClientsRegistrar这个类

public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) { 
   
		// 注册默认的配置类
		registerDefaultConfiguration(metadata, registry);
		// 注册feign客户端
		registerFeignClients(metadata, registry);
	}

我们看registerFeignClients里面有这样几行代码

		BeanDefinitionBuilder definition = BeanDefinitionBuilder
				.genericBeanDefinition(FeignClientFactoryBean.class);
		AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
		boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null
		beanDefinition.setPrimary(primary);
		String qualifier = getQualifier(attributes);
		if (StringUtils.hasText(qualifier)) { 
   
			alias = qualifier;
		}
		BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
				new String[] { 
    alias });
		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);

我们发现注册了一个FeignClientFactoryBean的类,它实现了FactoryBean,它提供了一个getObject方法,当我们依赖注入一个feign客户端对象的时候,这个方法就会被调用

public Object getObject() throws Exception { 
   
        // 获取FeignContext 对象
		FeignContext context = applicationContext.getBean(FeignContext.class);
		// 构建一个Feign.Builder 对象
		Feign.Builder builder = feign(context);
		if (!StringUtils.hasText(this.url)) { 
   
			String url;
			if (!this.name.startsWith("http")) { 
   
				url = "http://" + this.name;
			}
			else { 
   
				url = this.name;
			}
			url += cleanPath();
			return loadBalance(builder, context, new HardCodedTarget<>(this.type,
					this.name, url));
		}
		if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) { 
   
			this.url = "http://" + this.url;
		}
		String url = this.url + cleanPath();
		Client client = getOptional(context, Client.class);
		if (client != null) { 
   
			if (client instanceof LoadBalancerFeignClient) { 
   
				client = ((LoadBalancerFeignClient)client).getDelegate();
			}
			builder.client(client);
		}
		Targeter targeter = get(context, Targeter.class);
		return targeter.target(this, builder, context, new HardCodedTarget<>(
				this.type, this.name, url));
	}

1.获取FeignContext 对象,FeignContext 是怎么来的?
有一个自动装配类FeignAutoConfiguration,创建了这个对象
FeignAutoConfiguration类

@Bean
	public FeignContext feignContext() { 
   
		FeignContext context = new FeignContext();
		context.setConfigurations(this.configurations);
		return context;
	}

而且我们发现创建FeignContext中还调用了父类的构造器,传入了一个FeignClientsConfiguration
fegin会根据不同的服务创建不同的spring上下文,在创建不同的应用上下文时,这个类会被加载到上下文当中

FeignContext类

	public FeignContext() { 
   
		super(FeignClientsConfiguration.class, "feign", "feign.client.name");
	}

FeignClientsConfiguration类
这个类创建了Decoder ,Encoder 对象,对数据进行编解码,相当于序列化和反序列化。有一个Contract对象,
这个对象是用的SpringMvcContract对象,这个对象是用来解析请求的一个模板的,不如请求方式,路径,参数等。
还有 Feign.Builder,日志工厂等对象。

@Configuration
public class FeignClientsConfiguration { 
   

	@Autowired
	private ObjectFactory<HttpMessageConverters> messageConverters;

	@Autowired(required = false)
	private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();

	@Autowired(required = false)
	private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();

	@Autowired(required = false)
	private Logger logger;

	@Bean
	@ConditionalOnMissingBean
	public Decoder feignDecoder() { 
   
		return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
	}

	@Bean
	@ConditionalOnMissingBean
	public Encoder feignEncoder() { 
   
		return new SpringEncoder(this.messageConverters);
	}

	@Bean
	@ConditionalOnMissingBean
	public Contract feignContract(ConversionService feignConversionService) { 
   
		return new SpringMvcContract(this.parameterProcessors, feignConversionService);
	}
		@Bean
	public FormattingConversionService feignConversionService() { 
   
		FormattingConversionService conversionService = new DefaultFormattingConversionService();
		for (FeignFormatterRegistrar feignFormatterRegistrar : feignFormatterRegistrars) { 
   
			feignFormatterRegistrar.registerFormatters(conversionService);
		}
		return conversionService;
	}

	@Configuration
	@ConditionalOnClass({ 
    HystrixCommand.class, HystrixFeign.class })
	protected static class HystrixFeignConfiguration { 
   
		@Bean
		@Scope("prototype")
		@ConditionalOnMissingBean
		@ConditionalOnProperty(name = "feign.hystrix.enabled")
		public Feign.Builder feignHystrixBuilder() { 
   
			return HystrixFeign.builder();
		}
	}

	@Bean
	@ConditionalOnMissingBean
	public Retryer feignRetryer() { 
   
		return Retryer.NEVER_RETRY;
	}

	@Bean
	@Scope("prototype")
	@ConditionalOnMissingBean
	public Feign.Builder feignBuilder(Retryer retryer) { 
   
		return Feign.builder().retryer(retryer);
	}

	@Bean
	@ConditionalOnMissingBean(FeignLoggerFactory.class)
	public FeignLoggerFactory feignLoggerFactory() { 
   
		return new DefaultFeignLoggerFactory(logger);
	}

2.构建一个Feign.Builder对象

protected Feign.Builder feign(FeignContext context) { 
   
		FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
		Logger logger = loggerFactory.create(this.type);

		// @formatter:off
		Feign.Builder builder = get(context, Feign.Builder.class)
				// required values
				.logger(logger)
				.encoder(get(context, Encoder.class))
				.decoder(get(context, Decoder.class))
				.contract(get(context, Contract.class));
		// @formatter:on

		configureFeign(context, builder);

		return builder;
	}

在上下文当中去获取Feign.Builder,并设置编码,解码器,模板解析,日志等,这些对象都是在FeignClientsConfiguration 这个类中创建的。

	protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
			HardCodedTarget<T> target) { 
   
		Client client = getOptional(context, Client.class);
		if (client != null) { 
   
			builder.client(client);
			Targeter targeter = get(context, Targeter.class);
			return targeter.target(this, builder, context, target);
		}

		throw new IllegalStateException(
				"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
	}

在loadBalance方法中,又在builder,设置了一个client 对象,这个对象是LoadBalancerFeignClient的这么一个对象,他在是FeignRibbonClientAutoConfiguration这个自动装备类,有个Import注解的内容加载了一个DefaultFeignLoadBalancedConfiguration对象,里面有如下代码

@Configuration
class DefaultFeignLoadBalancedConfiguration { 
   
	@Bean
	@ConditionalOnMissingBean
	public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
							  SpringClientFactory clientFactory) { 
   
		return new LoadBalancerFeignClient(new Client.Default(null, null),
				cachingFactory, clientFactory);
	}
}

feign类

  public <T> T target(Target<T> target) { 
   
      return build().newInstance(target);
    }

build返回了一个ReflectiveFeign对象

    public Feign build() { 
   
      SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
                                               logLevel, decode404);
      ParseHandlersByName handlersByName =
          new ParseHandlersByName(contract, options, encoder, decoder,
                                  errorDecoder, synchronousMethodHandlerFactory);
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
    }

ReflectiveFeign类
可以看到返回一个代理对象

  public <T> T newInstance(Target<T> target) { 
   
    // 通过contract 将一个个方法解析成MethodHandler对象。实际上是SynchronousMethodHandler
    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
    Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
    List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();

    for (Method method : target.type().getMethods()) { 
   
      if (method.getDeclaringClass() == Object.class) { 
   
        continue;
      } else if(Util.isDefault(method)) { 
   
        DefaultMethodHandler handler = new DefaultMethodHandler(method);
        defaultMethodHandlers.add(handler);
        methodToHandler.put(method, handler);
      } else { 
   
        methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
      }
    }
    InvocationHandler handler = factory.create(target, methodToHandler);
    // 返回一个动态代理对象
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{ 
   target.type()}, handler);

    for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { 
   
      defaultMethodHandler.bindTo(proxy);
    }
    return proxy;
  }
	static class FeignInvocationHandler implements InvocationHandler { 
   

    private final Target target;
    private final Map<Method, MethodHandler> dispatch;

    FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) { 
   
      this.target = checkNotNull(target, "target");
      this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
   
      if ("equals".equals(method.getName())) { 
   
        try { 
   
          Object
              otherHandler =
              args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
          return equals(otherHandler);
        } catch (IllegalArgumentException e) { 
   
          return false;
        }
      } else if ("hashCode".equals(method.getName())) { 
   
        return hashCode();
      } else if ("toString".equals(method.getName())) { 
   
        return toString();
      }
      return dispatch.get(method).invoke(args);
    }

通过contract 将一个个方法解析成MethodHandler对象。实际上是SynchronousMethodHandler。
当请求过来后会进入到FeignInvocationHandlerinvoke方法,最后获取相应的MethodHandler去执行

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/188893.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • LoadImage()的使用

    LoadImage()的使用

    2021年12月6日
    54
  • java去重复元素并打印_Java打印数组中重复元素

    java去重复元素并打印_Java打印数组中重复元素Java打印数组中重复元素1说明在此程序中,我们需要打印数组中存在的重复元素。这可以通过两个循环来完成。第一个循环将选择一个元素,第二个循环将通过将所选元素与其他元素进行比较来遍历整个数组。如果找到匹配项,则打印重复的元素。在上面的数组中,第一个重复项将在索引4处找到,它是索引1处存在的元素(2)的重复项。因此,上面的数组中的重复元素是2、3和8。2算法思路步骤1:开始步骤2:初始化arr[…

    2022年4月30日
    69
  • LCD背光驱动IC「建议收藏」

    LCD背光驱动IC「建议收藏」对于40Pin标准RGBLCD,需要背光驱动电路,现有如下三种参考设计,这三种均是恒流驱动:1.UM1661(某宝价格1元左右)输入:2~6V  输出电压:高达24V 内部开关频率:2MHZ 最大输出电流:1.6A EN脚可接入PWM信号,实现PWM调光100-100KHZ参考电路如下:Iout=0.2V/5=40ma MBRA160T3G(60V1A)对于40…

    2022年4月18日
    249
  • 树莓派是什么?能干什么?

    树莓派是什么?能干什么?树莓派是什么?能干什么?一、什么是树莓派?二、树莓派和单片机的区别?三、树莓派使用的什么系统?四、树莓派的最基本操作方法?五、树莓派能干什么?六、玩树莓派能学到什么?一、什么是树莓派?树莓派是由树莓派基金会发布的卡片式电脑,起初的目的是为了让更多的孩子们可以学习计算机编程,但是发布以后受到了广大计算机爱好者的喜爱树莓派被称为卡片式电脑,顾名思义它可以安装操作系统,并且接上显示屏鼠标键盘就可以正常使用,在上面可以用python或者C语言编程并运行。二、树莓派和单片机的区别?树莓派是卡片式电脑可以装

    2022年6月8日
    28
  • k8s 开源_jdk源码剖析手册

    k8s 开源_jdk源码剖析手册createfunc main() { #随机数 rand.Seed(time.Now().UnixNano()) #创建一个新的命令行对象 command := cmd.NewDefaultKubectlCommand() #日志 logs.InitLogs() defer logs.FlushLogs() #真正执行的命令行 if err := command.Execute(); err != nil { os.Exit(1) }}# NewDefaultKubectl

    2022年8月11日
    5
  • 电阻电容电感的常用标注方法(手机电容和电阻的区分)

    认识电容及电容电阻的标注   一、认识电容及电容的标注①电容的功能和表示方法。由两个金属极,中间夹有绝缘介质构成。电容的特性主要是隔直流通交流,因此多用于级间耦合、滤波、去耦、旁路及信号调谐。电容在电路中用“C”加数字表示,比如C8,表示在电路中编号为8的电容。②电容的分类。电容按介质不同分为:气体介质电容,液体介质电容,无机固体介质电容,有机固体介质电容电解电容。按极性分为:有极性电容和无极性电

    2022年4月12日
    139

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号