环境:springboot2.2.13.RELEASE + springcloud Hoxton.SR8
1 开启Feign功能
@SpringCloudApplication @ServletComponentScan @EnableFeignClients("com.pack.feign") public class BaseApplication extends SpringBootServletinitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(BaseApplication.class); } public static void main(String[] args) { SpringApplication.run(BaseApplication.class, args); } }
查看EnableFeignClients源码
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients { }
@Import导入了其它类,关于@Import的使用已经介绍过了。直接查看FeignClientsRegistrar
查看核心代码
@Override public void registerBeanDeFinitions(AnnotationMetadata Metadata, BeanDeFinitionRegistry registry) { registerDefaultConfiguration(Metadata, registry); registerFeignClients(Metadata, registry); }
registerFeignClients方法用来扫描指定包下带有@FeignClient注解的类然后注册为Bean。
2 注册FeignClientBean
扫描及注册Bean
public void registerFeignClients(AnnotationMetadata Metadata, BeanDeFinitionRegistry registry) { ClasspathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader); Set<String> basePackages; // 获取添加注解@EnableFeignClients时的相关配置信息 Map<String, Object> attrs = Metadata .getAnnotationAttributes(EnableFeignClients.class.getName()); // 设置过滤条件,只匹配带有@FeignClient的注解 AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter( FeignClient.class); final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients"); if (clients == null || clients.length == 0) { // 过滤条件添加到Scanner中 scanner.addIncludeFilter(annotationTypeFilter); // 获取设置的扫描包信息 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))); } // 根据设置的包路径,查找符合条件的组件Bean for (String basePackage : basePackages) { Set<BeanDeFinition> 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"); Map<String, Object> attributes = annotationMetadata .getAnnotationAttributes( FeignClient.class.getCanonicalName()); String name = getClientName(attributes); registerClientConfiguration(registry, name, attributes.get("configuration")); // 真正注册Bean registerFeignClient(registry, annotationMetadata, attributes); } } } }
过滤符合条件的Class
private Set<BeanDeFinition> scanCandidateComponents(String basePackage) { Set<BeanDeFinition> candidates = new LinkedHashSet<>(); String packageSearchPath = ResourcePatternResolver.CLAsspATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); for (Resource resource : resources) { if (resource.isReadable()) { try { MetadataReader MetadataReader = getMetadataReaderFactory().getMetadataReader(resource); if (isCandidateComponent(MetadataReader)) { ScannedGenericBeanDeFinition sbd = new ScannedGenericBeanDeFinition(MetadataReader); sbd.setSource(resource); if (isCandidateComponent(sbd)) { if (debugEnabled) { logger.debug("Identified candidate component class: " + resource); } candidates.add(sbd); } } } } } return candidates; }
查找到所有符合条件的Bean后,接下来就是注册Bean
private void registerFeignClient(BeanDeFinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { String className = annotationMetadata.getClassName(); 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")); 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; } BeanDeFinitionHolder holder = new BeanDeFinitionHolder(beanDeFinition, className, new String[] { alias }); BeanDeFinitionReaderUtils.registerBeanDeFinition(holder, registry); }
注意下面这行代码
BeanDeFinitionBuilder deFinition = BeanDeFinitionBuilder.genericBeanDeFinition(FeignClientfactorybean.class);
FeignClientfactorybean是一个工厂Bean,实现了factorybean。仅凭一个接口就能调用方法肯定是被代理了。
到这里我们的Feign 相关的Bean就已经注册完了。接下来看看在执行过程中是如何使用的。
3 Feign如何被注入
准备业务代码
@FeignClient(value = "his-insurance") public interface MedicareSettingFeign { @GetMapping("/medicareSetting/queryInsuranceManageInfo") public R queryRoles(@RequestParam InsuranceManageQueryDTO queryDTO) ; } @RestController @RequestMapping("/feign") public class FeignDemoController { @Resource private MedicareSettingFeign feign ; @GetMapping("/invoke") public Object invoke(InsuranceManageQueryDTO dto) { return feign.queryRoles(dto) ; } }
当容器在实例化FeignDemoController时,是通过
CommonAnnotationBeanPostProcessor注入MedicareSettingFeign的,接下来查看这个过程
3.1 获取Bean对象
DefaultListablebeanfactory
最后进入到
AbstractAutowireCapablebeanfactory类中的如下方法
protected Object doCreateBean(String beanName, RootBeanDeFinition mbd, @Nullable Object[] args) throws BeanCreationException { // ... try { populateBean(beanName, mbd, instanceWrapper); exposedobject = initializeBean(beanName, exposedobject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean Failed", ex); } } // ... }
3.1.1 填充Bean属性
protected void populateBean(String beanName, RootBeanDeFinition mbd, @Nullable BeanWrapper bw) { // 核心代码 for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; PropertyValues pvsToUse = ibp.postProcessproperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.postProcesspropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } }
protected void populateBean(String beanName, RootBeanDeFinition mbd, @Nullable BeanWrapper bw) { // 核心代码 for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; PropertyValues pvsToUse = ibp.postProcessproperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.postProcesspropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } }
这里主要就是执行
CommonAnnotationBeanPostProcessor处理器的postProcessproperties来处理属性注入。
注入方法
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Collection<InjectedElement> checkedElements = this.checkedElements; Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { element.inject(target, beanName, pvs); } } }
通过反射设置Bean的属性
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable { if (this.isField) { Field field = (Field) this.member; ReflectionUtils.makeAccessible(field); field.set(target, getResourcetoInject(target, requestingBeanName)); } else { // ... } }
target为目标对象(Controller),getResourcetoInject方法获取要注入的资源对象
protected Object getResourcetoInject(Object target, @Nullable String requestingBeanName) { return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) : getResource(this, requestingBeanName)); }
进入getResource
protected Object getResource(LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDeFinitionException { return autowireResource(this.resourceFactory, element, requestingBeanName); }
一路调试最后会进入到Abstractbeanfactory
接着进入到
doGetobjectFromfactorybean方法调用factorybean的getobject方法
3.1.2 获取Feign接口的代理对象
private Object doGetobjectFromfactorybean(factorybean<?> factory, String beanName) throws BeanCreationException { Object object; try { if (System.getSecurityManager() != null) { AccessControlContext acc = getAccessControlContext(); try { object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getobject, acc); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { object = factory.getobject(); } } // ... return object; }
@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)); }
通过loadBalance方法最后进入到ReflectiveFeign中
3.1.3 创建代理对象
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; }
通过JDK创建动态代理对象,其中InvocationHandler使用的是HystrixInvocationHandler对象;通过这个Handler名称也知道Feign调用是具有熔断功能的。
final class HystrixInvocationHandler implements InvocationHandler { @Override public Object invoke(final Object proxy, final Method method, final 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(); } 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); if (isReturnsHystrixCommand(method)) { return ((HystrixCommand) result).execute(); } else if (isReturnsObservable(method)) { // Create a cold Observable return ((Observable) result).toBlocking().first(); } else if (isReturnsSingle(method)) { // Create a cold Observable as a Single return ((Single) result).toObservable().toBlocking().first(); } else if (isReturnsCompletable(method)) { ((Completable) result).await(); return null; } else if (isReturnsCompletableFuture(method)) { return ((Future) result).get(); } else { return result; } } catch (illegalaccessexception e) { // shouldn't happen as method is public due to being an interface throw new AssertionError(e); } catch (InvocationTargetException | ExecutionException e) { // Exceptions on fallback are tossed by Hystrix throw new AssertionError(e.getCause()); } catch (InterruptedException e) { // Exceptions on fallback are tossed by Hystrix Thread.currentThread().interrupt(); throw new AssertionError(e.getCause()); } } }; if (Util.isDefault(method)) { return hystrixCommand.execute(); } else if (isReturnsHystrixCommand(method)) { return hystrixCommand; } else if (isReturnsObservable(method)) { // Create a cold Observable return hystrixCommand.toObservable(); } else if (isReturnsSingle(method)) { // Create a cold Observable as a Single return hystrixCommand.toObservable().toSingle(); } else if (isReturnsCompletable(method)) { return hystrixCommand.toObservable().toCompletable(); } else if (isReturnsCompletableFuture(method)) { return new ObservableCompletableFuture<>(hystrixCommand); } return hystrixCommand.execute(); } }
这里Feign的代理对象就创建完成并且注入到了Controller中。
4 Feign接口调用
所有接口调用的入口都是在HystrixInvocationHandler中的invoke方法中
HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
这里的invoke是调用的SynchronousMethodHandler中的方法
@Override public Object invoke(Object[] argv) throws Throwable { RequestTemplate template = buildTemplateFromArgs.create(argv); Options options = findOptions(argv); Retryer retryer = this.retryer.clone(); while (true) { try { return executeAndDecode(template, options); } catch (RetryableException e) { try { retryer.continueOrPropagate(e); } catch (RetryableException th) { Throwable cause = th.getCause(); if (propagationPolicy == UNWRAP && cause != null) { throw cause; } else { throw th; } } if (logLevel != Logger.Level.NONE) { logger.logRetry(Metadata.configKey(), logLevel); } continue; } } }
最终业务的执行
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable { Request request = targetRequest(template); if (logLevel != Logger.Level.NONE) { logger.logRequest(Metadata.configKey(), logLevel, request); } Response response; long start = System.nanoTime(); try { response = client.execute(request, options); // ensure the request is set. Todo: remove in Feign 12 response = response.toBuilder() .request(request) .requestTemplate(template) .build(); } catch (IOException e) { if (logLevel != Logger.Level.NONE) { logger.logIOException(Metadata.configKey(), logLevel, e, elapsedtime(start)); } throw errorExecuting(request, e); } long elapsedtime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); if (decoder != null) return decoder.decode(response, Metadata.returnType()); CompletableFuture<Object> resultFuture = new CompletableFuture<>(); asyncResponseHandler.handleResponse(resultFuture, Metadata.configKey(), response, Metadata.returnType(), elapsedtime); try { if (!resultFuture.isDone()) throw new IllegalStateException("Response handling not done"); return resultFuture.join(); } catch (CompletionException e) { Throwable cause = e.getCause(); if (cause != null) throw cause; throw e; } }
完毕!!!
给个关注+转发呗谢谢
公众:Springboot实战案例锦集
关注 - 0
粉丝 - 0 0 0 « 上一篇: Springboot整合百度开源分布式ID生成器UIDGenerator posted @ 2021-07-10 07:42 FastCoder 阅读(4) 评论(0) 编辑 收藏 举报
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。