Spring Cloud Feign源码解析
我们知道要使用feign,需要在springboot启动类放入@EnableFeignClients开关来打开feign的使用。
@EnableFeignClients @EnableZuulProxy @EnableDiscoveryClient @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
然后会使用例如
@FeignClient("user-center") public interface UserClient { @PostMapping("/users-anon/finduser") LoginAppUser findUserByName(@RequestParam("username") String username); }
现在我们可以考虑的方向是打上了@FeignClient("user-center")标签后,UserClient接口是如何被实例化成对象的,然后是在Controller中调用UserClient对象是如何进行网络请求的。
@Slf4j @RestController public class TokenController { @Autowired private Oauth2Client oauth2Client; @Autowired private UserClient userClient; /** * 系统登陆<br> * 根据用户名登录<br> * 采用oauth2密码模式获取access_token和refresh_token * * @param username * @param password * @return */ @SuppressWarnings("unchecked") @PostMapping("/sys/login") public Result<Map> login(@RequestParam String username,@RequestParam String password) { Map<String, String> parameters = new HashMap<>(); parameters.put(OAuth2Utils.GRANT_TYPE, "password"); parameters.put(OAuth2Utils.CLIENT_ID, "system"); parameters.put("client_secret", "system"); parameters.put(OAuth2Utils.SCOPE, "app"); // parameters.put("username", username); // 为了支持多类型登录,这里在username后拼装上登录类型 parameters.put("username", username + "|" + CredentialType.USERNAME.name()); parameters.put("password", password); Map<String, Object> tokenInfo = oauth2Client.postAccessToken(parameters); AppUser user = userClient.findUserByName(username); tokenInfo.put("user",user); saveLoginLog(username, "用户名密码登陆"); return Result.success(tokenInfo); }
在feign的框架源码中,有3个类是比较重要的,FeignClientFactoryBean,FeignContext,SynchronousMethodHandler.
我们先来看一下@EnableFeignClients的作用。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) //用于处理@FeignClient注解 public @interface EnableFeignClients { //以下这三个都是用于指定需要扫描的包 String[] value() default {}; String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; //用于自定义feign client的自定义配置,可以配置Decoder(解码器),Encoder(编码器)和Contract等组件, //FeignClientsConfiguration是默认的配置类 Class<?>[] defaultConfiguration() default {}; //指定被@FeignClient修饰的类,如果不为空,那么路径自动检测机制会被关闭 Class<?>[] clients() default {}; }
@Import注解有四个作用
- 声明一个bean
- 导入@Configuration注解的配置类
- 导入ImportSelector的实现类
- 导入ImportBeanDefinitionRegistrar的实现类
FeignClientsRegistrar是用来处理@FeignClient修饰的FeignClient接口类,将这些接口类的BeanDefinition注册到Spring容器中,这样就可以使用@Autowired等方式来自动装载这些@FeignClient接口类的Bean实例。
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware
FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar接口,该接口是Spring实现bean动态注入的。我们来看一下该接口的方法
public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
在FeignClientsRegistrar中的实现
@Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //从EnableFeignClients的属性值来构建Feign的自定义Configuration进行注册 registerDefaultConfiguration(metadata, registry); //扫描package,注册被@FeignClient修饰的接口类的Bean信息 registerFeignClients(metadata, registry); }
private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //将@EnableFeignClients的所有属性值导入map中 Map<String, Object> defaultAttrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName(), true); //如果@EnableFeignClients配置了defaultConfiguration,则往下运行。如果没有,rantion //会使用默认的FeignConfiguration,一般我们这里不会设置这些配置,都是默认,但是如果设置了, //就会好比我们自己写了@Configuration的类一样的效果,这里是自动配置了 if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) { String name; //如果原始类中有内部类,获取内部类名 if (metadata.hasEnclosingClass()) { name = "default." + metadata.getEnclosingClassName(); } //否则获取原始类名 else { name = "default." + metadata.getClassName(); } //注册@EnableFeignClients的Configuration配置 registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration")); } }
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { //获取一个FeignClientSpecification的建造器 BeanDefinitionBuilder builder = BeanDefinitionBuilder .genericBeanDefinition(FeignClientSpecification.class); //传入构造参数 builder.addConstructorArgValue(name); builder.addConstructorArgValue(configuration); //将FeignClientSpecification当成内部类对象进行注册 registry.registerBeanDefinition( name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition()); }
以上这里可以方便我们学习怎么写一个标签达到自动配置效果。以下是扫描包,并把打了@FeignClient标签的接口给加载到Spring容器中。
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //获取扫描器 ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader); Set<String> basePackages; //将@EnableFeignClients的所有自定义配置属性放入内存map中 Map<String, Object> attrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName()); //初始化一个@FeignClient的标签类型过滤器 AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter( FeignClient.class); //如果设置了@EnableFeignClients的自定义配置,获取clients配置项中的Class数组 final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients"); //如果没有自定义配置 if (clients == null || clients.length == 0) { //扫描器添加标签过滤类型 scanner.addIncludeFilter(annotationTypeFilter); //获取默认配置扫描包集合 basePackages = getBasePackages(metadata); } else { //如果有自定义配置 final Set<String> clientClasses = new HashSet<>(); basePackages = new HashSet<>(); //遍历配置的每一个client Class for (Class<?> clazz : clients) { //添加每一个client Class的包 basePackages.add(ClassUtils.getPackageName(clazz)); //添加每一个client Class的类名(包含内部类名) 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))); } //遍历扫描包集合 for (String basePackage : basePackages) { //用扫描器扫描包,获取bean集合 Set<BeanDefinition> candidateComponents = scanner .findCandidateComponents(basePackage); //遍历扫描到的bean集合 for (BeanDefinition candidateComponent : candidateComponents) { //如果该bean为一个标签定义的bean if (candidateComponent instanceof AnnotatedBeanDefinition) { // verify annotated class is an interface AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; //获取该bean的元数据 AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); //断言该bean为一个接口(Interface) Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface"); //获取@FeignClient的所有属性放入map中 Map<String, Object> attributes = annotationMetadata .getAnnotationAttributes( FeignClient.class.getCanonicalName()); //获取@FeignClient配置的name(name或者value或者serviceId必须配置一个,并取其一) String name = getClientName(attributes); //注册单个@FeignClient的Configuration配置 registerClientConfiguration(registry, name, attributes.get("configuration")); //注册@FeignClient定义的bean registerFeignClient(registry, annotationMetadata, attributes); } } } }
这里我们需要看一下@FeignClient标签有哪些属性
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FeignClient { /** * name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现 */ @AliasFor("name") String value() default ""; /** * name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现 */ @Deprecated String serviceId() default ""; /** * name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现 */ @AliasFor("value") String name() default ""; /** * 限定符 */ String qualifier() default ""; /** * url一般用于调试,可以手动指定@FeignClient调用的地址 */ String url() default ""; /** * 当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException */ boolean decode404() default false; /** * Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract */ Class<?>[] configuration() default {}; /** * 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口 */ Class<?> fallback() default void.class; /** * 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码 */ Class<?> fallbackFactory() default void.class; /** * 定义当前FeignClient的统一前缀 */ String path() default ""; /** * 标记feign代理为主bean */ boolean primary() default true; }
private String getClientName(Map<String, Object> client) { if (client == null) { return null; } //获取@FeignClient配置的value String value = (String) client.get("value"); if (!StringUtils.hasText(value)) { //如果value为空,获取@FeignClient配置的name value = (String) client.get("name"); } if (!StringUtils.hasText(value)) { //如果value为空,获取@FeignClient配置的serviceId value = (String) client.get("serviceId"); } //如果value不为空,返回value if (StringUtils.hasText(value)) { return value; } throw new IllegalStateException("Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName()); }
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { //获取被@FeignClient标签注解的类名称,这里是接口名 String className = annotationMetadata.getClassName(); //设置bean建造器的bean工厂 BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); //断言@FeignClient配置的fallback,fallbackFactory必须为接口 validate(attributes); //建造器添加@FeignClient各配置属性 definition.addPropertyValue("url", getUrl(attributes)); definition.addPropertyValue("path", getPath(attributes)); String name = getName(attributes); definition.addPropertyValue("name", name); definition.addPropertyValue("type", className); definition.addPropertyValue("decode404", attributes.get("decode404")); definition.addPropertyValue("fallback", attributes.get("fallback")); definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory")); definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); String alias = name + "FeignClient"; //使用该建造器建造bean AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); //获取主bean标识 boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null //设置该bean是否为主bean beanDefinition.setPrimary(primary); //通过@FeignClient设置的限定符属性获取别名 String qualifier = getQualifier(attributes); if (StringUtils.hasText(qualifier)) { alias = qualifier; } //初始化一个bean的类名、别名解析器 BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); //通过bean工厂和别名解析器,将该bean注册到spring容器中 BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); }
private void validate(Map<String, Object> attributes) { AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes); // This blows up if an aliased property is overspecified // FIXME annotation.getAliasedString("name", FeignClient.class, null); Assert.isTrue( !annotation.getClass("fallback").isInterface(), "Fallback class must implement the interface annotated by @FeignClient" ); Assert.isTrue( !annotation.getClass("fallbackFactory").isInterface(), "Fallback factory must produce instances of fallback classes that implement the interface annotated by @FeignClient" ); }
我们在这里看到了FeignClientFactoryBean的工厂类,它的作用就是实例化bean的,由于我们的bean是接口,要实例化成对象,我们需要来看一下它的getObject()方法。
@Override public Object getObject() throws Exception { //在Spring容器中拿取FeignContext对象bean FeignContext context = applicationContext.getBean(FeignContext.class); //从feignContext上下文中获取Feign的建造器 Feign.Builder builder = feign(context); //如果在@FeignClient中未设置url属性 if (!StringUtils.hasText(this.url)) { String url; //如果@FeignClient的name属性以"http"开头 if (!this.name.startsWith("http")) { //设置url的值为http://name url = "http://" + this.name; } else { //否则设置url为name 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) { // not lod 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 targeter.target(this, builder, context, new HardCodedTarget<>( this.type, this.name, url)); }
protected Feign.Builder feign(FeignContext context) { FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class); Logger logger = loggerFactory.create(this.type); //从上下文中获取Feign的建造器bean实例builder 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; }
protected void configureFeign(FeignContext context, Feign.Builder builder) { FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class); if (properties != null) { if (properties.isDefaultToProperties()) { configureUsingConfiguration(context, builder); configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder); configureUsingProperties(properties.getConfig().get(this.name), builder); } else { configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder); configureUsingProperties(properties.getConfig().get(this.name), builder); configureUsingConfiguration(context, builder); } } else { configureUsingConfiguration(context, builder); } }
protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) { Logger.Level level = getOptional(context, Logger.Level.class); if (level != null) { builder.logLevel(level); } Retryer retryer = getOptional(context, Retryer.class); if (retryer != null) { builder.retryer(retryer); } ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class); if (errorDecoder != null) { builder.errorDecoder(errorDecoder); } Request.Options options = getOptional(context, Request.Options.class); if (options != null) { builder.options(options); } Map<String, RequestInterceptor> requestInterceptors = context.getInstances( this.name, RequestInterceptor.class); if (requestInterceptors != null) { builder.requestInterceptors(requestInterceptors.values()); } if (decode404) { builder.decode404(); } }
protected <T> T getOptional(FeignContext context, Class<T> type) { return context.getInstance(this.name, type); }
protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) { //Client是一个进行Http请求的类,为后续的第二个问题打下伏笔 Client client = getOptional(context, Client.class); if (client != null) { //建造器拼装client对象 builder.client(client); //从本身名称的上下文中获取Targeter的bean实例,这里Targeter是一个接口 //它有两个实现类DefaultTargeter,HystrixTargeter //这里进行了分岔,看上下文中注册的是使用默认的Targeter还是熔断器的Targeter Targeter targeter = get(context, Targeter.class); //根据上下文中不同的注册调用不同对象的target方法,这里我们具体看DefaultTargeter的方法 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?"); }
interface Targeter { <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target); }
class DefaultTargeter implements Targeter { @Override public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target) { //直接调用Feign建造器的方法 return feign.target(target); } }
在Feign中
public <T> T target(Target<T> target) { return build().newInstance(target); }
由于Feign是一个抽象类,这个newInstance为一个抽象方法
public abstract <T> T newInstance(Target<T> target);
在ReflectiveFeign中,ReflectiveFeign为Feign的子类,可以说前面所有的铺垫就是为了这个方法。
@SuppressWarnings("unchecked") @Override public <T> T newInstance(Target<T> target) { //Target是一个接口,我们这里传入的是它的内部实现类HardCodedTarget //获取目标的方法的方法名和方法处理器映射 Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target); Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>(); List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>(); //遍历目标type(被@FeignClinet注解的接口)的所有方法 for (Method method : target.type().getMethods()) { if (method.getDeclaringClass() == Object.class) { //如果目标type为Object,跳到下一个method,这里是说方法不来自普通类的顶层父类Object,按道理目标type(Class)不会为普通类,只是接口 continue; } else if(Util.isDefault(method)) { //如果该方法为接口默认方法,即被default修饰的方法 //初始化一个默认方法处理器对象 DefaultMethodHandler handler = new DefaultMethodHandler(method); //将该处理器对象添加到defaultMethodHandlers列表中 defaultMethodHandlers.add(handler); //将该处理器对象添加到methodToHandler映射中 methodToHandler.put(method, handler); } else { //如果不是默认方法,从nameToHandler中取出方法处理器并放入methodToHandler映射中 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; }
//MethodMetadata各属性 private String configKey; private transient Type returnType; private Integer urlIndex; private Integer bodyIndex; private Integer headerMapIndex; private Integer queryMapIndex; private boolean queryMapEncoded; private transient Type bodyType; private RequestTemplate template = new RequestTemplate(); private List<String> formParams = new ArrayList<String>(); private Map<Integer, Collection<String>> indexToName = new LinkedHashMap<Integer, Collection<String>>(); private Map<Integer, Class<? extends Expander>> indexToExpanderClass = new LinkedHashMap<Integer, Class<? extends Expander>>(); private Map<Integer, Boolean> indexToEncoded = new LinkedHashMap<Integer, Boolean>(); private transient Map<Integer, Expander> indexToExpander;
private final SynchronousMethodHandler.Factory factory; //同步方法处理器工厂
public Map<String, MethodHandler> apply(Target key) { //获取目标对象的type(Class类)属性的方法元数据列表 //这里的type其实就是被@FeignClient注解的接口,而接口的方法就是类似诸如 //@PostMapping("/users-anon/finduser") //LoginAppUser findUserByName(@RequestParam("username") String username); List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type()); Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>(); //遍历所有的方法元数据 for (MethodMetadata md : metadata) { BuildTemplateByResolvingArgs buildTemplate; //如果方法参数为@RequestParam,不为@RequestBody if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) { //构造一个BuildFormEncodedTemplateFromArgs对象,BuildFormEncodedTemplateFromArgs是BuildTemplateByResolvingArgs的子类 buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder); } else if (md.bodyIndex() != null) { //如果方法参数为@RequestBody,构造BuildEncodedTemplateFromArgs对象,BuildEncodedTemplateFromArgs也为BuildTemplateByResolvingArgs的子类 buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder); } else { //如果没有参数,构造BuildTemplateByResolvingArgs对象 buildTemplate = new BuildTemplateByResolvingArgs(md); } //创建一个方法处理器,并放入到方法配置映射中 result.put(md.configKey(), factory.create(key, md, buildTemplate, options, decoder, errorDecoder)); } return result; }
public MethodHandler create(Target<?> target, MethodMetadata md, RequestTemplate.Factory buildTemplateFromArgs, Options options, Decoder decoder, ErrorDecoder errorDecoder) { return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger, logLevel, md, buildTemplateFromArgs, options, decoder, errorDecoder, decode404); }
public static String configKey(Class targetType, Method method) { StringBuilder builder = new StringBuilder(); //拼装类名+“#”+方法名+“(” builder.append(targetType.getSimpleName()); builder.append('#').append(method.getName()).append('('); //遍历方法的参数类型 for (Type param : method.getGenericParameterTypes()) { //根据参数类型的所有可能进行处理,获取处理结果的类型 param = Types.resolve(targetType, targetType, param); //拼接该类型的类名称 builder.append(Types.getRawType(param).getSimpleName()).append(','); } //如果方法有参数 if (method.getParameterTypes().length > 0) { //移除最末尾的字符 builder.deleteCharAt(builder.length() - 1); } //移除后拼装),然后返回 return builder.append(')').toString(); }
static Type resolve(Type context, Class<?> contextRawType, Type toResolve) { // This implementation is made a little more complicated in an attempt to avoid object-creation. while (true) { //如果参数类型为泛型 if (toResolve instanceof TypeVariable) { //强制转化为泛型 TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve; //获取泛型的类型 toResolve = resolveTypeVariable(context, contextRawType, typeVariable); if (toResolve == typeVariable) { //返回该泛型的类型 return toResolve; } } else if (toResolve instanceof Class && ((Class<?>) toResolve).isArray()) { //如果参数类型为数组,将参数类型转化为类 Class<?> original = (Class<?>) toResolve; //获取数组的原类型,数组的原类型如果不是多维数组就不可能还是数组 Type componentType = original.getComponentType(); //递归调用,获取新的类型 Type newComponentType = resolve(context, contextRawType, componentType); //如果新类型为数组原类型,返回原参数类型的类(数组类型),否则返回封装了新类型的泛型数组类型对象,该对象的类实现 //泛型数组类型接口 return componentType == newComponentType ? original : new GenericArrayTypeImpl( newComponentType); } else if (toResolve instanceof GenericArrayType) { //如果参数类型为泛型数组类型 GenericArrayType original = (GenericArrayType) toResolve; //获取该泛型 Type componentType = original.getGenericComponentType(); //递归调用,获取新类型 Type newComponentType = resolve(context, contextRawType, componentType); //如果新类型就为该泛型,返回原参数类型(转化为泛型数组类型),否则返回封装了新类型的泛型数组类型对象,该对象的类实现 //泛型数组类型接口 return componentType == newComponentType ? original : new GenericArrayTypeImpl( newComponentType); } else if (toResolve instanceof ParameterizedType) { //如果参数类型为参数化类型 ParameterizedType original = (ParameterizedType) toResolve; //获取该参数化类型的外部类 Type ownerType = original.getOwnerType(); //递归调用获取新外部类型 Type newOwnerType = resolve(context, contextRawType, ownerType); //判断新外部类型与原外部类型是否不同 boolean changed = newOwnerType != ownerType; //获取参数化类型的所有参数类型 Type[] args = original.getActualTypeArguments(); //遍历所有参数类型 for (int t = 0, length = args.length; t < length; t++) { //递归调用每一个参数类型获取对应的新的类型 Type resolvedTypeArgument = resolve(context, contextRawType, args[t]); //如果对应的新类型不同于原参数类型 if (resolvedTypeArgument != args[t]) { //如果新外部类型为原外部类型 if (!changed) { //克隆新内存地址 args = args.clone(); //设定新外部类型与原外部类型不同 changed = true; } //将新类型放入原参数类型数组中 args[t] = resolvedTypeArgument; } } //如果新外部类型与原外部类型不同,返回封装了新外部类型和原内部类以及参数化多参数数组的参数化类型对象 //否则返回原参数化类型 return changed ? new ParameterizedTypeImpl(newOwnerType, original.getRawType(), args) : original; } else if (toResolve instanceof WildcardType) { //如果参数类型为通配符表达式类型,通配符表达式类型例如<? extends String>、<? super String> WildcardType original = (WildcardType) toResolve; //获取通配符前类型数组 Type[] originalLowerBound = original.getLowerBounds(); //获取通配符后类型数组 Type[] originalUpperBound = original.getUpperBounds(); //如果通配符下界类型可以获取 if (originalLowerBound.length == 1) { //递归调用,获取新下界类型 Type lowerBound = resolve(context, contextRawType, originalLowerBound[0]); //如果新下界类型与原下界不同 if (lowerBound != originalLowerBound[0]) { //返回封装了以Object.class为上界类型,新下界类型为下界类型的通配符类型对象 return new WildcardTypeImpl(new Type[]{Object.class}, new Type[]{lowerBound}); } } else if (originalUpperBound.length == 1) { //如果通配符上界类型可以获取 //递归调用,获取新上界类型 Type upperBound = resolve(context, contextRawType, originalUpperBound[0]); //如果新上界类型与原上界类型不同 if (upperBound != originalUpperBound[0]) { //返回封装了以新上界类型为上界类型,空为下界类型的通配符类型对象 return new WildcardTypeImpl(new Type[]{upperBound}, EMPTY_TYPE_ARRAY); } } //如果以上都没有,返回原类型 return original; } else { //其他情况返回原参数类型 return toResolve; } } }
private static Type resolveTypeVariable( Type context, Class<?> contextRawType, TypeVariable<?> unknown) { //获取泛型所在的类(Class) Class<?> declaredByRaw = declaringClassOf(unknown); //如果获取为null,直接返回该泛型 if (declaredByRaw == null) { return unknown; } //检测泛型所在类与目标类的关系(同类或者祖类),并取得目标类的该祖类(同类则相等,祖类则祖类与泛型所在类相等) Type declaredBy = getGenericSupertype(context, contextRawType, declaredByRaw); //如果该泛型所在类为参数化类型(例如List<String> list的List<String> 为参数化类型ParameterizedType) if (declaredBy instanceof ParameterizedType) { //获取泛型在泛型所在类的第几个参数 int index = indexOf(declaredByRaw.getTypeParameters(), unknown); //返回该泛型类型 return ((ParameterizedType) declaredBy).getActualTypeArguments()[index]; } return unknown; }
private static Class<?> declaringClassOf(TypeVariable<?> typeVariable) { //获取泛型所在的类 GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration(); //如果泛型所在的是类的话,返回该类(Class) return genericDeclaration instanceof Class ? (Class<?>) genericDeclaration : null; }
static Type getGenericSupertype(Type context, Class<?> rawType, Class<?> toResolve) { //如果泛型所属的类为目标类,返回目标类 if (toResolve == rawType) { return context; } //如果泛型所属的类并非目标类,说明是父类的 //且泛型所属的类为接口 if (toResolve.isInterface()) { //获取目标类(其实是接口)的所有父接口 Class<?>[] interfaces = rawType.getInterfaces(); //遍历所有的父接口 for (int i = 0, length = interfaces.length; i < length; i++) { //如果泛型所属的类为其中之一 if (interfaces[i] == toResolve) { //返回目标类的带泛型的父接口 return rawType.getGenericInterfaces()[i]; } else if (toResolve.isAssignableFrom(interfaces[i])) { //如果泛型所属的类为目标类父接口的父接口 //递归调用,一直查找到泛型所属的类匹配上目标类的某一个上层接口(祖先接口)为止,返回目标类带泛型的祖先接口 return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve); } } } //如果目标类不为接口(这个几乎不可能) if (!rawType.isInterface()) { //当目标类不为对象类时 while (rawType != Object.class) { //获取目标类的父类 Class<?> rawSupertype = rawType.getSuperclass(); //如果目标类的父类为泛型所属类 if (rawSupertype == toResolve) { //返回目标类带泛型的父类 return rawType.getGenericSuperclass(); } else if (toResolve.isAssignableFrom(rawSupertype)) { //如果泛型所属类为目标类父类的父类 //递归调用,一直查找到泛型所属的类匹配上目标类的某一个祖类为止,返回目标类带泛型的祖类 return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve); } //不断向祖类查找,直到找到对象类(Object类)为止 rawType = rawSupertype; } } //如果实在找不到,返回泛型所属类(Class是Type接口的实现类) return toResolve; }
private static int indexOf(Object[] array, Object toFind) { for (int i = 0; i < array.length; i++) { if (toFind.equals(array[i])) { return i; } } throw new NoSuchElementException(); }
static Class<?> getRawType(Type type) { if (type instanceof Class<?>) { //如果type为普通类,返回type return (Class<?>) type; } else if (type instanceof ParameterizedType) { //如果type为参数化类型 ParameterizedType parameterizedType = (ParameterizedType) type; //获取带参数化类型本身的类型 Type rawType = parameterizedType.getRawType(); //如果该类型不为类抛出异常 if (!(rawType instanceof Class)) { throw new IllegalArgumentException(); } //返回该类型的类 return (Class<?>) rawType; } else if (type instanceof GenericArrayType) { //如果type为泛型数组类型 //获取数组的原泛型 Type componentType = ((GenericArrayType) type).getGenericComponentType(); //返回数组的类class [Ljava.lang.Object; return Array.newInstance(getRawType(componentType), 0).getClass(); } else if (type instanceof TypeVariable) { //如果type为泛型 //返回Object类 return Object.class; } else if (type instanceof WildcardType) { //如果type为通配符类型 //返回通配符上界类型递归后的结果 return getRawType(((WildcardType) type).getUpperBounds()[0]); } else { //都不是则抛出异常 String className = type == null ? "null" : type.getClass().getName(); throw new IllegalArgumentException("Expected a Class, ParameterizedType, or " + "GenericArrayType, but <" + type + "> is of type " + className); } }
@Override public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) { return new ReflectiveFeign.FeignInvocationHandler(target, dispatch); }
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); } @Override public boolean equals(Object obj) { if (obj instanceof FeignInvocationHandler) { FeignInvocationHandler other = (FeignInvocationHandler) obj; return target.equals(other.target); } return false; } @Override public int hashCode() { return target.hashCode(); } @Override public String toString() { return target.toString(); } }
在Contract中
@Override public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) { //检查传入的Class是否有参数,有参数会报错 checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s", targetType.getSimpleName()); //检查传入的Class(一般为接口)是否有多个父接口,有多个父接口会报错,最多支持一个父接口 checkState(targetType.getInterfaces().length <= 1, "Only single inheritance supported: %s", targetType.getSimpleName()); //如果传入的Class有一个接口 if (targetType.getInterfaces().length == 1) { //检查该接口是否有祖父接口,有会抛出异常,不允许父接口还有父接口 checkState(targetType.getInterfaces()[0].getInterfaces().length == 0, "Only single-level inheritance supported: %s", targetType.getSimpleName()); } Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>(); //遍历传入的Class的所有方法 for (Method method : targetType.getMethods()) { //如果传入的Class为Object或者该方法为静态方法或者该方法为接口默认方法 if (method.getDeclaringClass() == Object.class || (method.getModifiers() & Modifier.STATIC) != 0 || Util.isDefault(method)) { //跳到下一个method continue; } //将传入的Class和每一个method解析为方法元数据 MethodMetadata metadata = parseAndValidateMetadata(targetType, method); checkState(!result.containsKey(metadata.configKey()), "Overrides unsupported: %s", metadata.configKey()); //将元数据放入map中 result.put(metadata.configKey(), metadata); } //返回符合条件的元数据列表 return new ArrayList<MethodMetadata>(result.values()); }
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) { //初始化一个方法元数据对象 MethodMetadata data = new MethodMetadata(); //设置该对象的返回类型 data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType())); //设置该对象的configKey data.configKey(Feign.configKey(targetType, method)); //如果目标类(接口)有一个父接口 if(targetType.getInterfaces().length == 1) { processAnnotationOnClass(data, targetType.getInterfaces()[0]); } processAnnotationOnClass(data, targetType); for (Annotation methodAnnotation : method.getAnnotations()) { processAnnotationOnMethod(data, methodAnnotation, method); } checkState(data.template().method() != null, "Method %s not annotated with HTTP method type (ex. GET, POST)", method.getName()); Class<?>[] parameterTypes = method.getParameterTypes(); Type[] genericParameterTypes = method.getGenericParameterTypes(); Annotation[][] parameterAnnotations = method.getParameterAnnotations(); int count = parameterAnnotations.length; for (int i = 0; i < count; i++) { boolean isHttpAnnotation = false; if (parameterAnnotations[i] != null) { isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i); } if (parameterTypes[i] == URI.class) { data.urlIndex(i); } else if (!isHttpAnnotation) { checkState(data.formParams().isEmpty(), "Body parameters cannot be used with form parameters."); checkState(data.bodyIndex() == null, "Method has too many Body parameters: %s", method); data.bodyIndex(i); data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i])); } } if (data.headerMapIndex() != null) { checkMapString("HeaderMap", parameterTypes[data.headerMapIndex()], genericParameterTypes[data.headerMapIndex()]); } if (data.queryMapIndex() != null) { checkMapString("QueryMap", parameterTypes[data.queryMapIndex()], genericParameterTypes[data.queryMapIndex()]); } return data; }
以下这个processAnnotationOnClass为SpringMvcContract中的,而不是Default中的。
@Override protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) { //如果父接口没有父接口 if (clz.getInterfaces().length == 0) { RequestMapping classAnnotation = findMergedAnnotation(clz, RequestMapping.class); if (classAnnotation != null) { // Prepend path from class annotation if specified if (classAnnotation.value().length > 0) { String pathValue = emptyToNull(classAnnotation.value()[0]); pathValue = resolve(pathValue); if (!pathValue.startsWith("/")) { pathValue = "/" + pathValue; } data.template().insert(0, pathValue); } } } }
/* * AnnotatedElement是所有可注释元素(可以是Class,Method,Field,Constructor,Package等)的接口 */ @Nullable public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement element, Class<A> annotationType) { //如果该元素不为类,但这里传进来的是目标接口的父接口 if (!(element instanceof Class)) { //获取该元素的注释 A annotation = element.getAnnotation(annotationType); if (annotation != null) { return AnnotationUtils.synthesizeAnnotation(annotation, element); } } // Exhaustive retrieval of merged annotation attributes... AnnotationAttributes attributes = findMergedAnnotationAttributes(element, annotationType, false, false); return (attributes != null ? AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element) : null); }
在NamedContextFactory中,NamedContextFactory是FeignContext的父类,并且是一个抽象类
这里我们可以看到NamedContextFactory实现了ApplicationContextAware接口,即可以获取Spring上下文。
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification> implements DisposableBean, ApplicationContextAware
//NamedContextFactory的内部接口 public interface Specification { String getName(); //获取配置类数组 Class<?>[] getConfiguration(); }
//名称与标签配置Spring上下文容器的映射,AnnotationConfigApplicationContext是专门用来做标签配置加载Spring应用上下文。 //从而避免使用xml配置 private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
//名称与内部接口实现类的映射 private Map<String, C> configurations = new ConcurrentHashMap<>();
//默认配置类 private Class<?> defaultConfigType;
protected <T> T get(FeignContext context, Class<T> type) { //从本身名称的上下文中获取type类的bean实例 T instance = context.getInstance(this.name, type); if (instance == null) { throw new IllegalStateException("No bean found of type " + type + " for " + this.name); } return instance; }
public <T> T getInstance(String name, Class<T> type) { //获取该名称的上下文,如果该名称的上下文不存在,则创建一个新的 AnnotationConfigApplicationContext context = getContext(name); //如果type类在该名称上下文中有注册的bean,此处type不能为一个接口 if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0) { //返回该名称上下文中的bean return context.getBean(type); } return null; }
protected AnnotationConfigApplicationContext getContext(String name) { //如果contexts中不包含该名称 if (!this.contexts.containsKey(name)) { synchronized (this.contexts) { //对contexts进行同步锁定 if (!this.contexts.containsKey(name)) { //创建一个新的context,并放入contexts中 this.contexts.put(name, createContext(name)); } } } //返回该名称的标签配置上下文 return this.contexts.get(name); }
protected AnnotationConfigApplicationContext createContext(String name) { //初始化一个标签配置上下文对象 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); //如果内部接口实现类映射中包含该名称 if (this.configurations.containsKey(name)) { //遍历该名称的内部接口实现类的所有配置类(数组) for (Class<?> configuration : this.configurations.get(name) .getConfiguration()) { //将每一个配置类注册到标签配置上下文中 context.register(configuration); } } //遍历内部接口实现类的每一对映射 for (Map.Entry<String, C> entry : this.configurations.entrySet()) { //如果名称以"default."开头 if (entry.getKey().startsWith("default.")) { //遍历该名称的内部接口实现类的所有配置类(数组) for (Class<?> configuration : entry.getValue().getConfiguration()) { //将每一个配置类注册到标签配置上下文中 context.register(configuration); } } } //注册自动装配类和默认配置类 context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType); context.getEnvironment().getPropertySources().addFirst(new MapPropertySource( this.propertySourceName, Collections.<String, Object> singletonMap(this.propertyName, name))); if (this.parent != null) { // Uses Environment from parent as well as beans context.setParent(this.parent); } context.setDisplayName(generateDisplayName(name)); //以上注册的bean,context必须刷新才可以使用 context.refresh(); return context; }
在BeanFactoryUtils中,首先我们要先看一张AnnotationConfigApplicationContext继承图,图中表明AnnotationConfigApplicationContext是实现了ListableBeanFactory接口的。
由以下代码可以看出,此处是找出一个Class在Spring上下文中,无论是在哪一个层级的上下文(Spring有很多层级的上下文,就上面这张图里标示出来的)注册的,都可以找出来,并把这些类名称放到一个数组中。如果Class是一个接口,则可以找出它所有的被注册到Spring容器的实现类(如果未被Spring上下文注册是找不到的)
public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class<?> type) { //这里我们把ListableBeanFactory lbf就看成标签配置上下文AnnotationConfigApplicationContext对象 //断言上下文对象不能为null Assert.notNull(lbf, "ListableBeanFactory must not be null"); //获取type的所有类名称(这里包括父类和所有子类) String[] result = lbf.getBeanNamesForType(type); //此处为真,因为AnnotationConfigApplicationContext也实现了HierarchicalBeanFactory接口 if (lbf instanceof HierarchicalBeanFactory) { //强制转化成HierarchicalBeanFactory(有分层的bean工厂)接口的实例 HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; //如果hbf的父bean工厂为ListableBeanFactory(可列表的bean工厂) if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { //递归hbf的父bean工厂,获取父bean工厂中,type的所有类名称(父子类) String[] parentResult = beanNamesForTypeIncludingAncestors( (ListableBeanFactory) hbf.getParentBeanFactory(), type); //组合当前结果和父bean工厂的结果 result = mergeNamesWithParent(result, parentResult, hbf); } } //返回该结果 return result; }
private static String[] mergeNamesWithParent(String[] result, String[] parentResult, HierarchicalBeanFactory hbf) { //如果type在父bean工厂没有类名称,直接返回result if (parentResult.length == 0) { return result; } //组合当前结果和父bean工厂结果数组 List<String> merged = new ArrayList<>(result.length + parentResult.length); merged.addAll(Arrays.asList(result)); for (String beanName : parentResult) { if (!merged.contains(beanName) && !hbf.containsLocalBean(beanName)) { merged.add(beanName); } } //将组合结果由List转回数组返回 return StringUtils.toStringArray(merged); }
- spring cloud openfeign 源码实例解析
- spring cloud feign 运用与源码解析
- 网关 Spring-Cloud-Gateway 源码解析 —— 调试环境搭建
- 网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化
- 网关 Spring-Cloud-Gateway 源码解析 —— 调试环境搭建
- 网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化
- Spring-Cloud-Gateway 源码解析 —— 路由(2.4)之 Kotlin 自定义 RouteLocator
- 网关 Spring-Cloud-Gateway 源码解析 —— 调试环境搭建
- 网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化
- Spring Cloud部分源码分析Eureka,Ribbon,Feign,Zuul
- 网关 Spring-Cloud-Gateway 源码解析 —— 调试环境搭建
- SpringCloud 查找调用REST服务使用RestTemplate(ribbon负载)或feign模式 教程源码 火推
- spring-cloud源码解析-hystrix的基本介绍和配置属性说明
- spring cloud config server源码解析
- 【SpringCloud】Netflix源码解析之Ribbon:负载均衡策略的定义和实现
- 网关 Spring-Cloud-Gateway 源码解析 —— 调试环境搭建
- 网关 Spring-Cloud-Gateway 源码解析 —— 调试环境搭建
- Spring-cloud & Netflix 源码解析:Eureka 服务注册发现接口 ****
- 网关 Spring-Cloud-Gateway 源码解析 —— 调试环境搭建
- Spring-cloud & Netflix 源码解析:Eureka 服务注册发现接口 ****