关于云计算:springcloudsquare源码速读retrofit-okhttp篇

25次阅读

共计 26810 个字符,预计需要花费 68 分钟才能阅读完成。

欢送拜访我的 GitHub

这里分类和汇总了欣宸的全副原创 (含配套源码):https://github.com/zq2599/blog_demos

spring-cloud-square 系列文章

  1. 五分钟搞懂 spring-cloud-square
  2. spring-cloud-square 开发实战 (三种类型全笼罩)
  3. spring-cloud-square 源码速读 (spring-cloud-square-okhttp 篇)
  4. spring-cloud-square 源码速读(retrofit + okhttp 篇)

本篇概览

  • 本文是《spring-cloud-square 学习》系列的终篇,上一篇咱们理解了 spring-cloud-square-okhttp 库的源码和原理,明天晋升一点难度,看看 spring-cloud-square 的另一种类型的源码:<font color=”blue”>spring-cloud-square-retrofit</font>,也就是下图红框中的那种:

源码剖析指标

  • 接下来开始剖析 spring-cloud-square-retrofit 工程的源码,如下图红框所示:

  • 本篇指标十分明确,只搞清楚一件事:在应用 spring-cloud-square 的时候,以前文的 consumer-retrofit-okhttp 子工程为例,为什么咱们只写了 HelloService 接口,但却能通过 Autowired 注解应用 HelloService 的实现类?

提前小结

  • 如果您想理解 spring-cloud-square 的 retrofit 局部的原理,却又苦于没有工夫深入研究,能够看看上面这份提前小结的内容:
  1. 整个机制的运行,能够分为绝对独立的四个局部:业务利用编码应用 spring-cloud-square 相干的注解、bean 的 factory 注册到 spring 环境、bean 的 factory 类在 spring 环境实例化、通过 factory 的实例在 spring 生产 HelloService 接口的实现类
  2. 依据下面的剖析,最重要的应该是 bean 的 factory 类:<font color=”blue”>RetrofitClientFactoryBean</font>,它实现了 FactoryBean 接口,其 getObject 办法就是依据 HelloService 接口生成实现类和要害,最终会调用下图红框中的 Retrofit.create 办法创立实例:

  1. Retrofit 类并非 spring-cloud 的我的项目,而是来自 Retrofit 库,其 create 办法中应用了 JDK 的 Proxy.newProxyInstance 办法,该办法能够依据 HelloService 接口生成一个实现了该接口的实例:

  1. 在应用 spring-cloud-square 的 retrofit + okhttp 计划时,HelloService 接口中应用的还是近程服务的服务名,而不是地址和端口,这是因为应用了 spring-cloud-square-okhttp 库,所以服务名转为 <font color=”red”> 地址 + 端口 </font> 的逻辑与前文《spring-cloud-square 源码速读 (spring-cloud-square-okhttp 篇)》保持一致
  • 以上就是整个源码剖析的论断了,我将波及到的关联代码流程整顿成简图,如下所示:

回顾利用如何应用 spring-cloud-square-retrofit

  • 在剖析源码之前,先回顾一下《spring-cloud-square 开发实战》中的代码,咱们过后是如何应用 <font color=”blue”>spring-cloud-square-retrofit</font> 的 (对应 demo 中的 consumer-retrofit-okhttp 子工程)
  1. 新建配置类 OkHttpClientConfig,应用了 EnableRetrofitClients 注解,向 spring 环境注册 OkHttpClient.Builder 实例:
@Configuration
@EnableRetrofitClients
class OkHttpClientConfig{
    @Bean
    @LoadBalanced
    public OkHttpClient.Builder okHttpClientBuilder() {return new OkHttpClient.Builder();
    }
}
  1. 定义 HelloService 接口,用注解 RetrofitClient 润饰,注解的值是近程调用的服务名 <font color=”blue”></font>,外面申明 hello 办法,用注解 GET 润饰,注解的值是近程调用的接口的 path:
@RetrofitClient("provider")
public interface HelloService {@GET("/hello-obj")
    Call<HelloResponse> hello(@Query("name") String name);
}
  1. 在业务要做近程调用的时候,用 Autowired 注解润饰 HelloService 接口,即可调用 HelloService.hello 办法,至于接口对应的实例来自哪里,开发者不用关注:
@RestController
public class RemoteHello {@Autowired(required = false)
    HelloService helloService;

    @GetMapping("/remote-obj")
    public HelloResponse hello(@RequestParam("name") String name) throws IOException {return helloService.hello(name).execute().body();
    }
}
  • 以上就是咱们开发业务代码时应用 spring-cloud-square 的要害操作,接下来就从源码角度来剖析这些操作到底施展了什么作用

源码剖析 (类定义注册阶段)

  • 回顾一下咱们写的 OkHttpClientConfig.java,外面应用了注解 <font color=”blue”>EnableRetrofitClients</font>,这就是本次浏览代码的入口:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({RetrofitConfiguration.class, RetrofitClientsRegistrar.class})
public @interface EnableRetrofitClients {String[] value() default {};
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
    Class<?>[] defaultConfiguration() default {};
    Class<?>[] clients() default {};}
  • 从上述代码可见 RetrofitConfiguration 和 RetrofitClientsRegistrar 都会比实例化,RetrofitConfiguration 过于简略就不看了,重点关注 RetrofitClientsRegistrar,先来看它的类图,搞清楚继承和实现
  • 如下图所示,RetrofitClientsRegistrar 集成自 AbstractRetrofitClientsRegistrar,而 AbstractRetrofitClientsRegistrar 又集成自 ImportBeanDefinitionRegistrar

  • 所以,RetrofitClientsRegistrar 被实例化的时候,就相当于 ImportBeanDefinitionRegistrar 接口的实现类被实例化了,这个 ImportBeanDefinitionRegistrar 接口,置信相熟 spring 的同学对其不会生疏,它是用来动静注册 bean 的,那么接下来的重点就是 ImportBeanDefinitionRegistrar 的 registerBeanDefinitions 办法的具体内容,看看它到底注册了什么 bean
  • registerBeanDefinitions 办法的代码在 AbstractRetrofitClientsRegistrar.java 中(请在下面的类图中找到 AbstractRetrofitClientsRegistrar 的地位),如下所示,因为 EnableRetrofitClients 润饰的是咱们创立的 OkHttpClientConfig.java,所以上面的入参 AnnotationMetadata 是 OkHttpClientConfig 类的注解信息:
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {registerDefaultConfiguration(metadata, registry);
        registerRetrofitClients(metadata, registry);
    }
  • 上述代码的第一个办法 registerDefaultConfiguration 是注册配置信息的,非重点,跳过
  • 上述代码的第二个办法 registerRetrofitClients,这是本篇的要害,请重点关注上面代码中的中文正文:
public void registerRetrofitClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(this.resourceLoader);

        Set<String> basePackages;

        Map<String, Object> attrs = metadata.getAnnotationAttributes(getAnnotationClass().getName());
        // 过滤条件:有 RetrofitClient 注解润饰的类,对应咱们代码中的 HelloService.java
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(RetrofitClient.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<>();
            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) {
                // 找到的后果就是 HelloService 接口
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    // verify annotated class is an interface
                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                    Assert.isTrue(annotationMetadata.isInterface(),
                            "@RetrofitClient can only be specified on an interface");

                    // 获得润饰 HelloService 类的 RetrofitClient 注解的所有属性
                    Map<String, Object> attributes = annotationMetadata
                            .getAnnotationAttributes(RetrofitClient.class.getCanonicalName());
                    // 依据这些属性,失去近程拜访的服务名是 provider
                    String name = getClientName(attributes);
                    // 在 spring 注册一个配置类,名为 provider.RetrofitClientSpecification,// 因为润饰 HelloService 的 RetrofitClient 注解并没有什么属性,所以这个配置类没有什么内容
                    registerClientConfiguration(registry, name, attributes.get("configuration"));
                    
                    // 这个办法要重点关注,// 入参 annotationMetadata 是 HelloService 的元信息,// attributes 是润饰 HelloService 类的 RetrofitClient 注解的所有属性
                    registerRetrofitClient(registry, annotationMetadata, attributes);
                }
            }
        }
    }
  • 将上述代码中最初调用的 registerRetrofitClient 办法开展如下,这段代码做了件很重要的事件:注册 BeanDefinition 到 spring,注册的 name 等于 <font color=”blue”>com.bolingcavalry.consumer.service.HelloService</font>,对应的 BeanDefinition 的 beanClass 等于 <font color=”red”>RetrofitClientFactoryBean</font>:
private void registerRetrofitClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
            Map<String, Object> attributes) {
        // 因为注解润饰的是 HelloService 类,所以这里 className 等于 com.bolingcavalry.consumer.service.HelloService
        String className = annotationMetadata.getClassName();
        // 留神 getFactoryBeanClass() 办法,来自 RetrofitClientsRegistrar 类,返回值是 RetrofitClientFactoryBean.class,// 因而,RetrofitClientFactoryBean 就被带入了 definition 中,// 留神,这个 definition 变量的类型是 BeanDefinitionBuilder,
        // 其外部有个成员变量 beanDefinition,此时该成员变量的 beanClass 字段曾经被设置为 RetrofitClientFactoryBean.class
        BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(getFactoryBeanClass());
        validate(attributes);
        // HelloService 的 RetrofitClient 注解没有设置 url 属性,因而这里是空字符串
        definition.addPropertyValue("url", getUrl(attributes));
        // RetrofitClient 注解的 value 属性配置为近程服务名,这里是 provider
        String name = getName(attributes);
        definition.addPropertyValue("name", name);
        // 类型就是 HelloService
        definition.addPropertyValue("type", className);
        // by_type,意味着 autowire 注解润饰 HelloService 的时候,能够用 HelloService 获取对应的实现类
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

        String alias = name + "RetrofitClient";
        
        // 通过 BeanDefinitionBuilder 失去了 beanDefinition,// 这个 beanDefinition 的 beanClass 字段在后面曾经被设置为 RetrofitClientFactoryBean.class
        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
        
        beanDefinition.setPrimary(true);

        String qualifier = getQualifier(attributes);
        if (StringUtils.hasText(qualifier)) {alias = qualifier;}
        
        // 将注册 BeanDefinition 所需的两个参数 beanName 和 beanDefinition 放入 BeanDefinitionHolder 对象中
        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] {alias});
        // 实现 BeanDefinition 在 spring 环境的注册,name 等于 com.bolingcavalry.consumer.service.HelloService,对应的 BeanDefinition 的 beanClass 等于 RetrofitClientFactoryBean(留神,这很重要)
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
    }
  • 此刻,HelloService 的类定义曾经在 spring 实现了注册,接下来要看 HelloService 接口的实现类来自何处;

BeanDefinition 中的 RetrofitClientFactoryBean 被实例化

  • 在 spring 初始化过程中,上述红框中的代码会触发 spring 环境对 HelloService 接口实现类的实例化,残缺的触发过程和具体堆栈就不细说了,这都是 spring 的规范解决流程,接下来会挑这外面的重点去看
  • 首先就是赫赫有名的 SpringApplication.refresh 办法,这外面是 bean 的实例化逻辑,会执行一个重要办法,就是 DefaultListableBeanFactory.doGetBeanNamesForType,这外面会遍历所有已注册的 BeanDefinition,一一解决,如下图:

  • DefaultListableBeanFactory.doGetBeanNamesForType 继续执行,会到下一个重点:依据 BeanDefinition 创立 bean,堆栈如下,这是用条件断点失去的:
doGetBean:256, AbstractBeanFactory (org.springframework.beans.factory.support) [2]
getTypeForFactoryBean:1709, AbstractBeanFactory (org.springframework.beans.factory.support)
getTypeForFactoryBean:899, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
isTypeMatch:637, AbstractBeanFactory (org.springframework.beans.factory.support)
doGetBeanNamesForType:583, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBeanNamesForType:542, DefaultListableBeanFactory (org.springframework.beans.factory.support)
beanNamesForTypeIncludingAncestors:265, BeanFactoryUtils (org.springframework.beans.factory)
findAutowireCandidates:1546, DefaultListableBeanFactory (org.springframework.beans.factory.support)
doResolveDependency:1343, DefaultListableBeanFactory (org.springframework.beans.factory.support)
resolveDependency:1300, DefaultListableBeanFactory (org.springframework.beans.factory.support)
resolveAutowiredArgument:887, ConstructorResolver (org.springframework.beans.factory.support)
createArgumentArray:791, ConstructorResolver (org.springframework.beans.factory.support)
instantiateUsingFactoryMethod:541, ConstructorResolver (org.springframework.beans.factory.support)
instantiateUsingFactoryMethod:1334, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBeanInstance:1177, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:564, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:524, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
lambda$doGetBean$0:335, AbstractBeanFactory (org.springframework.beans.factory.support)
getObject:-1, 1485624601 (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$488)
getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:333, AbstractBeanFactory (org.springframework.beans.factory.support) [1]
getBean:213, AbstractBeanFactory (org.springframework.beans.factory.support)
registerBeanPostProcessors:258, PostProcessorRegistrationDelegate (org.springframework.context.support)
registerBeanPostProcessors:762, AbstractApplicationContext (org.springframework.context.support)
refresh:567, AbstractApplicationContext (org.springframework.context.support)
refresh:769, SpringApplication (org.springframework.boot)
refresh:761, SpringApplication (org.springframework.boot)
refreshContext:426, SpringApplication (org.springframework.boot)
run:326, SpringApplication (org.springframework.boot)
loadContext:123, SpringBootContextLoader (org.springframework.boot.test.context)
loadContextInternal:99, DefaultCacheAwareContextLoaderDelegate (org.springframework.test.context.cache)
loadContext:124, DefaultCacheAwareContextLoaderDelegate (org.springframework.test.context.cache)
getApplicationContext:124, DefaultTestContext (org.springframework.test.context.support)
setUpRequestContextIfNecessary:190, ServletTestExecutionListener (org.springframework.test.context.web)
prepareTestInstance:132, ServletTestExecutionListener (org.springframework.test.context.web)
prepareTestInstance:244, TestContextManager (org.springframework.test.context)
postProcessTestInstance:138, SpringExtension (org.springframework.test.context.junit.jupiter)
lambda$invokeTestInstancePostProcessors$6:350, ClassBasedTestDescriptor (org.junit.jupiter.engine.descriptor)
execute:-1, 2001115307 (org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$344)
executeAndMaskThrowable:355, ClassBasedTestDescriptor (org.junit.jupiter.engine.descriptor)
lambda$invokeTestInstancePostProcessors$7:350, ClassBasedTestDescriptor (org.junit.jupiter.engine.descriptor)
accept:-1, 1650113431 (org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$343)
accept:-1, 796667727 (java.util.stream.StreamSpliterators$WrappingSpliterator$$Lambda$107)
accept:193, ReferencePipeline$3$1 (java.util.stream)
accept:175, ReferencePipeline$2$1 (java.util.stream)
forEachRemaining:1384, ArrayList$ArrayListSpliterator (java.util)
copyInto:482, AbstractPipeline (java.util.stream)
wrapAndCopyInto:472, AbstractPipeline (java.util.stream)
forEachRemaining:312, StreamSpliterators$WrappingSpliterator (java.util.stream)
forEachRemaining:743, Streams$ConcatSpliterator (java.util.stream)
forEachRemaining:742, Streams$ConcatSpliterator (java.util.stream)
forEach:580, ReferencePipeline$Head (java.util.stream)
invokeTestInstancePostProcessors:349, ClassBasedTestDescriptor (org.junit.jupiter.engine.descriptor)
lambda$instantiateAndPostProcessTestInstance$4:270, ClassBasedTestDescriptor (org.junit.jupiter.engine.descriptor)
execute:-1, 1547883191 (org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$342)
execute:73, ThrowableCollector (org.junit.platform.engine.support.hierarchical)
instantiateAndPostProcessTestInstance:269, ClassBasedTestDescriptor (org.junit.jupiter.engine.descriptor)
lambda$testInstancesProvider$2:259, ClassBasedTestDescriptor (org.junit.jupiter.engine.descriptor)
get:-1, 795748540 (org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$335)
orElseGet:267, Optional (java.util)
lambda$testInstancesProvider$3:258, ClassBasedTestDescriptor (org.junit.jupiter.engine.descriptor)
getTestInstances:-1, 361398902 (org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$234)
getTestInstances:31, TestInstancesProvider (org.junit.jupiter.engine.execution)
lambda$prepare$0:101, TestMethodTestDescriptor (org.junit.jupiter.engine.descriptor)
execute:-1, 451312813 (org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor$$Lambda$334)
execute:73, ThrowableCollector (org.junit.platform.engine.support.hierarchical)
prepare:100, TestMethodTestDescriptor (org.junit.jupiter.engine.descriptor)
prepare:65, TestMethodTestDescriptor (org.junit.jupiter.engine.descriptor)
lambda$prepare$1:111, NodeTestTask (org.junit.platform.engine.support.hierarchical)
execute:-1, 1008315045 (org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$182)
execute:73, ThrowableCollector (org.junit.platform.engine.support.hierarchical)
prepare:111, NodeTestTask (org.junit.platform.engine.support.hierarchical)
execute:79, NodeTestTask (org.junit.platform.engine.support.hierarchical)
accept:-1, 1976870338 (org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService$$Lambda$201)
forEach:1259, ArrayList (java.util)
invokeAll:38, SameThreadHierarchicalTestExecutorService (org.junit.platform.engine.support.hierarchical)
lambda$executeRecursively$5:143, NodeTestTask (org.junit.platform.engine.support.hierarchical)
execute:-1, 1647809929 (org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$197)
execute:73, ThrowableCollector (org.junit.platform.engine.support.hierarchical)
lambda$executeRecursively$7:129, NodeTestTask (org.junit.platform.engine.support.hierarchical)
invoke:-1, 928294079 (org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$196)
around:137, Node (org.junit.platform.engine.support.hierarchical)
lambda$executeRecursively$8:127, NodeTestTask (org.junit.platform.engine.support.hierarchical)
execute:-1, 728885526 (org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$195)
execute:73, ThrowableCollector (org.junit.platform.engine.support.hierarchical)
executeRecursively:126, NodeTestTask (org.junit.platform.engine.support.hierarchical)
execute:84, NodeTestTask (org.junit.platform.engine.support.hierarchical)
accept:-1, 1976870338 (org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService$$Lambda$201)
forEach:1259, ArrayList (java.util)
invokeAll:38, SameThreadHierarchicalTestExecutorService (org.junit.platform.engine.support.hierarchical)
lambda$executeRecursively$5:143, NodeTestTask (org.junit.platform.engine.support.hierarchical)
execute:-1, 1647809929 (org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$197)
execute:73, ThrowableCollector (org.junit.platform.engine.support.hierarchical)
lambda$executeRecursively$7:129, NodeTestTask (org.junit.platform.engine.support.hierarchical)
invoke:-1, 928294079 (org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$196)
around:137, Node (org.junit.platform.engine.support.hierarchical)
lambda$executeRecursively$8:127, NodeTestTask (org.junit.platform.engine.support.hierarchical)
execute:-1, 728885526 (org.junit.platform.engine.support.hierarchical.NodeTestTask$$Lambda$195)
execute:73, ThrowableCollector (org.junit.platform.engine.support.hierarchical)
executeRecursively:126, NodeTestTask (org.junit.platform.engine.support.hierarchical)
execute:84, NodeTestTask (org.junit.platform.engine.support.hierarchical)
submit:32, SameThreadHierarchicalTestExecutorService (org.junit.platform.engine.support.hierarchical)
execute:57, HierarchicalTestExecutor (org.junit.platform.engine.support.hierarchical)
execute:51, HierarchicalTestEngine (org.junit.platform.engine.support.hierarchical)
execute:108, EngineExecutionOrchestrator (org.junit.platform.launcher.core)
execute:88, EngineExecutionOrchestrator (org.junit.platform.launcher.core)
lambda$execute$0:54, EngineExecutionOrchestrator (org.junit.platform.launcher.core)
accept:-1, 607932305 (org.junit.platform.launcher.core.EngineExecutionOrchestrator$$Lambda$150)
withInterceptedStreams:67, EngineExecutionOrchestrator (org.junit.platform.launcher.core)
execute:52, EngineExecutionOrchestrator (org.junit.platform.launcher.core)
execute:96, DefaultLauncher (org.junit.platform.launcher.core)
execute:75, DefaultLauncher (org.junit.platform.launcher.core)
startRunnerWithArgs:71, JUnit5IdeaTestRunner (com.intellij.junit5)
startRunnerWithArgs:33, IdeaTestRunner$Repeater (com.intellij.rt.junit)
prepareStreamsAndStart:221, JUnitStarter (com.intellij.rt.junit)
main:54, JUnitStarter (com.intellij.rt.junit)
  • 根据上述堆栈,要细看 AbstractBeanFactory 的 doGetBean 办法,请关注中文正文:
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
            throws BeansException {
        // 入参 name 等于 "com.bolingcavalry.consumer.service.HelloService"
        String beanName = transformedBeanName(name);
        Object beanInstance;

        // Eagerly check singleton cache for manually registered singletons.
        Object sharedInstance = getSingleton(beanName);
        // sharedInstance 等于 null,因而上面的 if 判断不成立
        if (sharedInstance != null && args == null) {if (logger.isTraceEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.trace("Returning eagerly cached instance of singleton bean'" + beanName +
                            "'that is not fully initialized yet - a consequence of a circular reference");
                }
                else {logger.trace("Returning cached instance of singleton bean'" + beanName + "'");
                }
            }
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            BeanFactory parentBeanFactory = getParentBeanFactory();
            // parentBeanFactory 等于 null,因而上面的 if 判断不成立
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else if (requiredType != null) {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
                else {return (T) parentBeanFactory.getBean(nameToLookup);
                }
            }
            
            // typeCheckOnly 等于 true,因而上面的 if 判断不成立
            if (!typeCheckOnly) {markBeanAsCreated(beanName);
            }

            StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
                    .tag("beanName", name);
            try {if (requiredType != null) {beanCreation.tag("beanType", requiredType::toString);
                }
                // 后面咱们剖析过,BeanDefinition 曾经注册到 spring 环境了,// 此处调用 getMergedLocalBeanDefinition 即可获得这个 BeanDefinition
                RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                String[] dependsOn = mbd.getDependsOn();
                // HelloService 的 BeanDefinition 没有依赖,// 因而 dependsOn 等于 null,上面的 if 不成立
                if (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between'" + beanName + "'and'" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        try {getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'"+ beanName +"' depends on missing bean '"+ dep +"'", ex);
                        }
                    }
                }

                // Create bean instance.
                // HelloService 的 bean 是单例,因而上面的 if 判断成立
                if (mbd.isSingleton()) {
                    // 这里是创立 bean 的要害!!!// getSingleton 传入一个 lambda 表达式,办法内会调用该表达式,sharedInstance = getSingleton(beanName, () -> {
                        try {
                            // 依据 BeanDefinition 创立 bean,// 实际上执行的是 AbstractAutowireCapableBeanFactory.createBean 办法
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                    Object prototypeInstance = null;
                    try {beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {afterPrototypeCreation(beanName);
                    }
                    beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                else {String scopeName = mbd.getScope();
                    if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
                    }
                    Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {throw new IllegalStateException("No Scope registered for scope name'" + scopeName + "'");
                    }
                    try {Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);
                            try {return createBean(beanName, mbd, args);
                            }
                            finally {afterPrototypeCreation(beanName);
                            }
                        });
                        
                        beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {throw new ScopeNotActiveException(beanName, scopeName, ex);
                    }
                }
            }
            catch (BeansException ex) {beanCreation.tag("exception", ex.getClass().toString());
                beanCreation.tag("message", String.valueOf(ex.getMessage()));
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
            finally {beanCreation.end();
            }
        }

        return adaptBeanInstance(name, beanInstance, requiredType);
    }
  • 至此,RetrofitClientFactoryBean 曾经实现了实例化,接下来要去看 HelloService 接口背地的 bean 是怎么创立的

HelloService 对应的 bean 是如何创立的

  • 回顾一下,咱们的利用代码中用到 HelloService 的场景,如下图红框所示,应用 Autowired 注解润饰 HelloService:

  • 首先,上图中的 RemoteHello 是肯定会创立 bean 的,在创立的过程中,DefaultListableBeanFactory.doResolveDependency 办法负责解决 RemoteHello 依赖的 bean,如下图所示,在此处触发了 HelloService 的 bean 的实例化

  • 辗转反侧,再次走到了 AbstractBeanFactory.doGetBean 办法,这次会执行下图第二个红框中的 getObjectForBeanInstance 办法:

  • 而后到了最要害的地位:AbstractBeanFactory.getObjectForBeanInstance 办法,这外面将 RetrofitClientFactoryBean 当做 factory 用了,用来生产 HelloService:

  • 将上图红框 2 中的 getObjectFromFactoryBean 办法持续开展,进入 FactoryBeanRegistrySupport.doGetObjectFromFactoryBean 办法,这里实现了从 spring 框架到利用自定义之间的过渡:将 bean 的创立交给利用本人注册的 Factory 来解决:

  • 在 RetrofitClientFactoryBean.getObject 中,执行 loadBalance(builder, context, serviceIdUrl):

  • loadBalance 的实现在 RetrofitClientFactoryBean 中:
    protected Object loadBalance(Retrofit.Builder builder, RetrofitContext context, String serviceIdUrl) {
        // 利用代码的 OkHttpClientConfig.java 中,okHttpClientBuilder 办法生成了 OkHttpClient.Builder 实例,此处的 instances 中就是这个实例
        Map<String, OkHttpClient.Builder> instances = context.getInstances(this.name, OkHttpClient.Builder.class);
        
        for (Map.Entry<String, OkHttpClient.Builder> entry : instances.entrySet()) {String beanName = entry.getKey();
            OkHttpClient.Builder clientBuilder = entry.getValue();
            // 利用代码的 OkHttpClientConfig.java 中,okHttpClientBuilder 办法上曾经用了 LoadBalanced 注解,// 所以上面这个 if 判断为 true
            if (applicationContext.findAnnotationOnBean(beanName, LoadBalanced.class) != null) {
                // 创立了 OkHttpClient 实例,传给了这个 Retrofit.Builder
                builder.client(clientBuilder.build());
                // 应用这个 Retrofit.Builder 去创立 retrofit,相当于把下面创立的 OkHttpClient 实例带给了 retrofit
                // 所以,这个 retrofit 实例的底层就是 OkHttpClient
                Retrofit retrofit = buildAndSave(context, builder);
                // type 的类型是 HelloService,// retrofit.create 就是要创立一个实例, 该实例实现了 HelloService 接口
                return retrofit.create(this.type);
            }
        }

        throw new IllegalStateException("No Retrofit Client for loadBalancing defined. Did you forget to include spring-cloud-starter-square-okhttp?");
    }
  • 从下面的剖析可见,咱们只写 HelloService 接口不写 HelloService 实现的要害就是 retrofit.create 办法,传入了一个接口定义,就能返回该接口的实现类的实例
  • 说实话 retrofit.create 的源码并不属于 spring-cloud-square,而是 Retrofit 本人的,在本文中看这段源码属于超纲,但我还是忍不住要看一下:
  public <T> T create(final Class<T> service) {
      // 一些查看,例如 service 是不是接口
    validateServiceInterface(service);
    return (T)
        // 这个实例是通过 JDK 的 Proxy.newProxyInstance 创立的
        Proxy.newProxyInstance(service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {private final Platform platform = Platform.get();
              private final Object[] emptyArgs = new Object[0];
                
              // 业务利用执行 HelloService 的 hello 办法时,实际上执行的是上面的办法    
              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // If the method is a method from Object then defer to normal invocation.
                if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }
  • 至此终于真像大白,最终还是用 Proxy.newProxyInstance 生成了 HelloService 的代理类实例,作为 HelloService.hello 调用背地的真正实现
  • 最初仿佛还有一点疑难,就是 HelloService 的 RetrofitClient 注解的属性是服务名 provider,那么真正网络申请的时候,是如何转成实在的地址和端口的呢?
  • 再回头看看咱利用 consumer-retrofit-okhttp 的 pom.xml 文件,如下图红框所示,和前文一样,这里也应用了 spring-cloud-square-okhttp,而且咱们写的 OkHttpClientConfig.java 和前文也是一样的,所以,依据服务名获取地址和端口的操作仍旧能够用前文的剖析来解释:

  • 至于 HelloService.hello 办法,如何对应到 web 申请,请容我说一声:这是 retrofit 和 okhttp 之间的事件,在这里算是超纲了,篇幅所限,切实展不开了 …

尾记:对于另一种 spring-cloud-square 类型:retrofit + webflux

  • 之前的文章曾经剖析过,spring-cloud-square 一共有三种类型,如下图所示,两个绿框中的源码都剖析过了,还剩下的只有红色的 <font color=”blue”>retrofit + webflux</font> 组合:

  • 欣宸还要再写一篇 <font color=”blue”>retrofit + webflux</font> 源码剖析的文章?不不不,读源码太累,写出的文章,聪慧的您读起来也累,所以就此打住吧
  • 如果勤奋努力的您想独立浏览剖析 <font color=”blue”>retrofit + webflux</font> 源码,这里给您一个倡议,还记得本篇后面的那个类图吗,如下图,应用 <font color=”blue”>retrofit + webflux</font> 的时候,会用到 spring-cloud-square-retrofit-webclient.jar,这个 jar 外面也有 OkHttpClientConfig 注解,它的 import 会实例化下图红框中的类,这个类就是您浏览源码的入口:

  • 至此《spring-cloud-square 学习》系列曾经全副实现,心愿这四篇文章能够帮忙您全面把握 spring-cloud-square,在您的我的项目中对近程调用的操作更加得心应手;

你不孤独,欣宸原创一路相伴

  1. Java 系列
  2. Spring 系列
  3. Docker 系列
  4. kubernetes 系列
  5. 数据库 + 中间件系列
  6. DevOps 系列

欢送关注公众号:程序员欣宸

微信搜寻「程序员欣宸」,我是欣宸,期待与您一起畅游 Java 世界 …

https://github.com/zq2599/blog_demos

正文完
 0