一. @EnableFeignClients
1.1.类介绍
从上面注释可以看出是扫描声明了@FeignClient接口的类,还引入了 FeignClientsRegistrar类,从字面意思可以看出是进行了 FeignClient 客户端类的注册。
1.2.FeignClientsRegistrar 详解
最主要的一个方法:registerBeanDefinitions注册bean定义信息,主要功能是实现向容器注册Feign客户端配置信息和所有的使用了@FeignClient的类;
1.2.1.registerDefaultConfiguration()
private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { // 获取@EnableFeignClients注解的属性和值 MapdefaultAttrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName(), true); // 获取属性中的默认配置 defaultConfiguration,name是main主程序 if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) { String name; if (metadata.hasEnclosingClass()) { name = "default." + metadata.getEnclosingClassName(); } else { name = "default." + metadata.getClassName(); } //默认配置信息进行容器注册 registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration")); } }
1.2.1.1.registerClientConfiguration
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { // 创建一个 FeignClientSpecification.class 构造器 BeanDefinitionBuilder builder = BeanDefinitionBuilder .genericBeanDefinition(FeignClientSpecification.class); builder.addConstructorArgValue(name); builder.addConstructorArgValue(configuration); // 向容器中注册默认配置 registry.registerBeanDefinition( name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition()); }
1.2.1.2.registerBeanDefinition
核心代码在:org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { ............ if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { //放到beanDefinitionMap,到AbstractApplicationContext#finishBeanFactoryInitialization(beanFactory)中取出进行bean实例化 //此时是处于invokeBeanFactoryPostProcessors(beanFactory);阶段,进行BeanDefinitionRegistryPostProcessor的处理 this.beanDefinitionMap.put(beanName, beanDefinition); ListupdatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); } } .......... }
1.2.2.registerFeignClients()
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //获取一个扫描器 ClassPathScanningCandidateComponentProvider scanner = getScanner(); //设置资源路径 scanner.setResourceLoader(this.resourceLoader); //包路径 SetbasePackages; //获取EnableFeignClients注解的参数和值,有5个值,其中clients对应的class[0]是没有值的 Map attrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName()); //定义一个 FeignClient 注解类型过滤器 AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter( FeignClient.class); //clients为class[0],长度为0 final Class>[] clients = attrs == null ? null : (Class>[]) attrs.get("clients"); if (clients == null || clients.length == 0) { //FeignClient 注解过滤器添加到扫描器中 scanner.addIncludeFilter(annotationTypeFilter); //获取Application对应的根路径包 basePackages = getBasePackages(metadata); } //clients不为空:FeignClient 注解过滤器添加到扫描器中、获取包路径 else { final Set clientClasses = new HashSet<>(); basePackages = new HashSet<>(); for (Class> clazz : clients) { basePackages.add(ClassUtils.getPackageName(clazz)); clientClasses.add(clazz.getCanonicalName()); } AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() { @Override protected boolean match(ClassMetadata metadata) { String cleaned = metadata.getClassName().replaceAll("\\$", "."); return clientClasses.contains(cleaned); } }; scanner.addIncludeFilter( new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter))); } //遍历包路径,获取标记@FeignClient注解的接口向容器中注入 for (String basePackage : basePackages) { Set candidateComponents = scanner .findCandidateComponents(basePackage); for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { // verify annotated class is an interface AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface"); //获取@FeignClient的参数和值 Map attributes = annotationMetadata .getAnnotationAttributes( FeignClient.class.getCanonicalName()); String name = getClientName(attributes); //再次更新配置 registerClientConfiguration(registry, name, attributes.get("configuration")); //注册 registerFeignClient(registry, annotationMetadata, attributes); } } } }
1.2.2.2.registerFeignClient
//定义一个 FeignClientFactoryBean bean定义构造器(重点) BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class); .......... //前面根据attributes进行属性赋值后注入到Spring容器中 BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
二.@FeignClient
从上面可以看到在注册客户端时注册了一个FeignClientFactoryBean(对于FactoryBean的扩展知识和案例),所以FeignClient的获取是从getObject()获取的:
2.1.getTarget()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
//获取创建feign实例的工厂 FeignContext context = this .applicationContext.getBean(FeignContext. class ); //获取feign构造器 Feign.Builder builder = feign(context); //url拼接 if (!StringUtils.hasText( this .url)) { //拼接name if (! this .name.startsWith( "http" )) { this .url = "http://" + this .name; } else { this .url = this .name; } //拼接path this .url += cleanPath(); //创建实例 return (T) loadBalance(builder, context, new HardCodedTarget<>( this .type, this .name, this .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) { // not load balancing because we have a url, // but ribbon is on the classpath, so unwrap client = ((LoadBalancerFeignClient) client).getDelegate(); } builder.client(client); } Targeter targeter = get (context, Targeter. class ); return (T) targeter.target( this , builder, context, new HardCodedTarget<>( this .type, this .name, url)); } |
2.1.1. feign()
//添加日志对象、编码器、解码器、解析规则器 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)) //SpringMvcContract:对RequestMapping、RequestParam、RequestHeader等注解进行解析 .contract(get(context, Contract.class)); // @formatter:on configureFeign(context, builder); return builder; }
2.1.2. loadBalance()
protectedT loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget target) { //根据context上下文获取客户端实例,client:TraceLoadBalancerFeignClient,负载均衡 Client client = getOptional(context, Client.class); if (client != null) { //客户端创建 builder.client(client); //获取HystrixTargerer Targeter targeter = get(context, Targeter.class); //调用HystrixTargeter#target进行实例创建 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?"); }
2.1.3. HystrixTargeter#target
class HystrixTargeter implements Targeter { @Override publicT target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { // 不是同一种类型,进入feign#target方法 if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) { return feign.target(target); } ...... }
2.1.4. Feign.Builder#target
publicT target(Target target) { return build().newInstance(target); }
2.1.4.1. Feign.Builder#target
public Feign build() { //同步方法处理工厂,构建了日志级别信息 SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy); //解析信息:编码、解密、同步方法处理工厂 ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, errorDecoder, synchronousMethodHandlerFactory); //new对象 return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); }
2.1.4.2.ReflectiveFeign#newInstance
@Override publicT newInstance(Target target) { //得到feign类的定义方法 Map nameToHandler = targetToHandlersByName.apply(target); //定义方法存放集合 Map methodToHandler = new LinkedHashMap (); //默认方法存放集合 List defaultMethodHandlers = new LinkedList (); //对feign类方法进行遍历 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))); } } //jdk动态代理创建对象 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; }
三.总结
主要应用了FactoryBean的特性getObject()进行jdk动态创建一个ReflectiveFeign的代理对象。