标签:sam hand ddc qualifier state boot ble enc ret
compile ‘org.springframework.cloud:spring-cloud-starter-openfeign‘
@SpringBootApplication @EnableFeignClients(basePackages = {"com.yue.consumer"}) //开启 Feign支持,扫描指定包下接口 public class WebApplication { public static void main(String[] args) { SpringApplication.run(WebApplication.class, args); } //声明 feign接口 @FeignClient(name = "service-name", path = "/v1", url = "http://sck-demo-provider", primary = false) static interface FeignService { //调用服务接口 @RequestMapping("/test") public String getName(); } }
@RestController @RequestMapping("/test") public class TestController { @Autowired FeignService feignService; @RequestMapping("/getString") public String getStr(){ return feignService.getName(); } }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients { /** * basePackages 属性的别名。 允许使用更简洁的注释声明 */ String[] value() default {}; /** * 扫描包下带注释的组件 */ String[] basePackages() default {}; /** * basePackages() 的类型安全的替代方法,用于指定要扫描带注释的组件的软件包。 指定类别的包装将被扫描。 */ Class<?>[] basePackageClasses() default {}; /** * 适用于所有自定义@Configuration,可以包含组成客户端的部分的@Bean */ Class<?>[] defaultConfiguration() default {}; /** * 用@FeignClient注释的类的列表。 如果不为空,则禁用类路径*扫描。 */ Class<?>[] clients() default {}; }
FeignClientsRegistrar.class
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { // 获取 name static String getName(String name) { if (!StringUtils.hasText(name)) { return ""; } String host = null; try { String url; if (!name.startsWith("http://") && !name.startsWith("https://")) { url = "http://" + name; } else { url = name; } host = new URI(url).getHost(); } catch (URISyntaxException e) { } Assert.state(host != null, "Service id not legal hostname (" + name + ")"); return name; } //获取 url static String getUrl(String url) { if (StringUtils.hasText(url) && !(url.startsWith("#{") && url.contains("}"))) { if (!url.contains("://")) { url = "http://" + url; } try { new URL(url); } catch (MalformedURLException e) { throw new IllegalArgumentException(url + " is malformed", e); } } return url; } //获取 path static String getPath(String path) { if (StringUtils.hasText(path)) { path = path.trim(); if (!path.startsWith("/")) { path = "/" + path; } if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } } return path; } @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //注册configuration registerDefaultConfiguration(metadata, registry); //注册注解 registerFeignClients(metadata, registry); } private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { 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." + metadata.getClassName(); } //注册客户端配置 registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration")); } } private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { //加载FeignClientSpecification bean BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class); builder.addConstructorArgValue(name); builder.addConstructorArgValue(configuration); //注册 registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),builder.getBeanDefinition()); } public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader); Set<String> basePackages; Map<String, Object> attrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName()); // 扫描带有FeignClient注解的类 AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class); //获取@EnableFeignClients 中clients的值 final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients"); if (clients == null || clients.length == 0) { //如果没有设置,那么设置类型过滤器 scanner.addIncludeFilter(annotationTypeFilter); // 如果没有设置,则扫描的包路径为 @EnableFeignClients 注解所在的包 basePackages = getBasePackages(metadata); } else { final Set<String> 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))); } //循环扫描注册 for (String basePackage : basePackages) { Set<BeanDefinition> candidateComponents = scanner .findCandidateComponents(basePackage); for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { // 验证带注释的类必须是接口 AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); Assert.isTrue(annotationMetadata.isInterface(),"@FeignClient can only be specified on an interface"); Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName()); String name = getClientName(attributes); //注册客户端配置 registerClientConfiguration(registry, name, attributes.get("configuration")); //注册 FeignClient registerFeignClient(registry, annotationMetadata, attributes); } } } } private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { String className = annotationMetadata.getClassName(); //将属性设置到 FeignClientFactoryBean 中 BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes); definition.addPropertyValue("url", getUrl(attributes)); definition.addPropertyValue("path", getPath(attributes)); String name = getName(attributes); definition.addPropertyValue("name", name); String contextId = getContextId(attributes); definition.addPropertyValue("contextId", contextId); definition.addPropertyValue("type", className); definition.addPropertyValue("decode404", attributes.get("decode404")); definition.addPropertyValue("fallback", attributes.get("fallback")); definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory")); //设置 Autowire类型 definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); String alias = contextId + "FeignClient"; AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className); // has a default, won‘t be null boolean primary = (Boolean) attributes.get("primary"); beanDefinition.setPrimary(primary); String qualifier = getQualifier(attributes); if (StringUtils.hasText(qualifier)) { alias = qualifier; } //注册 BeanDefinition BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); } }
至此,注册完成,注意此时仅仅只是注册到 DefaultListableBeanFactory容器的 beanDefinitionMap中,并没有实例化!
@RestController @RequestMapping("/test") public class TestController { @Autowired FeignService feignService; @RequestMapping("/getString") public String getStr(){ return feignService.getName(); } }
在实例化 TestController 这个Bean后的填充属性阶段会去注入 FeignService 这个Bean。
如果你熟悉Spring 源码,那么知道 Bean的创建最终是通过 factory.getObject() 实现。
通过栈信息,可以很清晰的了解
FeignClient 的实例化 :factory.getObject() 是使用 FeignClientFactoryBean 类。
FeignClientFactoryBean.class
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware { @Override public Object getObject() throws Exception { return getTarget(); } <T> T getTarget() { FeignContext context = applicationContext.getBean(FeignContext.class); Feign.Builder builder = feign(context); if (!StringUtils.hasText(url)) { if (!name.startsWith("http")) { url = "http://" + name; } else { url = name; } url += cleanPath(); return (T) loadBalance(builder, context, new HardCodedTarget<>(type, name, url)); } if (StringUtils.hasText(url) && !url.startsWith("http")) { url = "http://" + 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(); } if (client instanceof FeignBlockingLoadBalancerClient) { // not load balancing because we have a url, // but Spring Cloud LoadBalancer is on the classpath, so unwrap client = ((FeignBlockingLoadBalancerClient) client).getDelegate(); } builder.client(client); } Targeter targeter = get(context, Targeter.class); return (T) targeter.target(this, builder, context, new HardCodedTarget<>(type, name, url)); } protected Feign.Builder feign(FeignContext context) { FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class); Logger logger = loggerFactory.create(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; } // 获取 Targeter protected <T> T get(FeignContext context, Class<T> type) { T instance = context.getInstance(contextId, type); if (instance == null) { throw new IllegalStateException( "No bean found of type " + type + " for " + contextId); } return instance; } 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?"); } }
在实例化之前在回顾下Spring SPI机制。
FeignAutoConfiguration.class
@Configuration(proxyBeanMethods = false) @ConditionalOnClass(Feign.class) @EnableConfigurationProperties({ FeignClientProperties.class, FeignHttpClientProperties.class }) @Import(DefaultGzipDecoderConfiguration.class) public class FeignAutoConfiguration { //如果配置了 feign.hystrix.HystrixFeign属性则加载此配置 @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "feign.hystrix.HystrixFeign") protected static class HystrixFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new HystrixTargeter(); } } //如果没有配置 feign.hystrix.HystrixFeign属性则加载此配置 @Configuration(proxyBeanMethods = false) @ConditionalOnMissingClass("feign.hystrix.HystrixFeign") protected static class DefaultFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new DefaultTargeter(); } } }
FeignClientsConfiguration.class
@Configuration(proxyBeanMethods = false) @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(); } }
HystrixTargeter.class
class HystrixTargeter implements Targeter { @Override public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target) { if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) { return feign.target(target); } feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign; String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName() : factory.getContextId(); SetterFactory setterFactory = getOptional(name, context, SetterFactory.class); if (setterFactory != null) { builder.setterFactory(setterFactory); } Class<?> fallback = factory.getFallback(); if (fallback != void.class) {
// 如果有配置 fallback return targetWithFallback(name, context, target, builder, fallback); } Class<?> fallbackFactory = factory.getFallbackFactory(); if (fallbackFactory != void.class) {
// 如果有配置 fallBackFactory return targetWithFallbackFactory(name, context, target, builder, fallbackFactory); } return feign.target(target); } }
HystrixFeign.class
public final class HystrixFeign { public <T> T target(Target<T> target, T fallback) { return build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null) .newInstance(target); } public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {
// 最终是在ReflectiveFeign 实现. return build(fallbackFactory).newInstance(target); } Feign build(final FallbackFactory<?> nullableFallbackFactory) { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) { return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory); } }); super.contract(new HystrixDelegatingContract(contract)); return super.build(); } }
HystrixInvocationHandler.class
final class HystrixInvocationHandler implements InvocationHandler { private final Target<?> target; private final Map<Method, MethodHandler> dispatch; private final FallbackFactory<?> fallbackFactory; // Nullable private final Map<Method, Method> fallbackMethodMap; private final Map<Method, Setter> setterMethodMap; HystrixInvocationHandler(Target<?> target, Map<Method, MethodHandler> dispatch, SetterFactory setterFactory, FallbackFactory<?> fallbackFactory) { this.target = checkNotNull(target, "target"); this.dispatch = checkNotNull(dispatch, "dispatch"); this.fallbackFactory = fallbackFactory; this.fallbackMethodMap = toFallbackMethod(dispatch); this.setterMethodMap = toSetters(setterFactory, target, dispatch.keySet()); } @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { // early exit if the invoked method is from java.lang.Object // code is the same as ReflectiveFeign.FeignInvocationHandler 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(); } HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) { @Override protected Object run() throws Exception { try { return HystrixInvocationHandler.this.dispatch.get(method).invoke(args); } catch (Exception e) { throw e; } catch (Throwable t) { throw (Error) t; } } @Override protected Object getFallback() { if (fallbackFactory == null) { return super.getFallback(); } try { Object fallback = fallbackFactory.create(getExecutionException()); Object result = fallbackMethodMap.get(method).invoke(fallback, args); ...省略 return hystrixCommand.execute(); } }
HystrixFeign父类 Feign类
public Feign build() { Client client = Capability.enrich(this.client, capabilities); Retryer retryer = Capability.enrich(this.retryer, capabilities); List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream() .map(ri -> Capability.enrich(ri, capabilities)) .collect(Collectors.toList()); Logger logger = Capability.enrich(this.logger, capabilities); Contract contract = Capability.enrich(this.contract, capabilities); Options options = Capability.enrich(this.options, capabilities); Encoder encoder = Capability.enrich(this.encoder, capabilities); Decoder decoder = Capability.enrich(this.decoder, capabilities); InvocationHandlerFactory invocationHandlerFactory = Capability.enrich(this.invocationHandlerFactory, capabilities); QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities); SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding); ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, errorDecoder, synchronousMethodHandlerFactory); return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); }
ReflectiveFeign.class
public class ReflectiveFeign extends Feign { private final ParseHandlersByName targetToHandlersByName; private final InvocationHandlerFactory factory; private final QueryMapEncoder queryMapEncoder; ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory, QueryMapEncoder queryMapEncoder) { this.targetToHandlersByName = targetToHandlersByName; this.factory = factory; this.queryMapEncoder = queryMapEncoder; } @Override public <T> T newInstance(Target<T> target) { 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; } }
标签:sam hand ddc qualifier state boot ble enc ret
原文地址:https://www.cnblogs.com/lucky-yqy/p/14589434.html