6.Dagger2.38.1源码解析-Resolved解析器

228 阅读7分钟

前言

这部分对前面的依赖非常大,这一部分的精华是Resolved解析:从component入口方法componentMethodEntryPoint开始,该入口方法的参数paramter作为当前需要注入实例的MembersInjectionObject对象,该MembersInjectionObject对象中使用的Inject修饰的变量或普通方法表示需要外部component容器实现实例化并且注入到MembersInjectionObject对象中的。

换成当前ComponentProcessor作为Demo来在描述一遍(灰常重要):

  1. 首先在ProcessorComponent接口中有一个inject方法表示入口方法:

     void inject(ComponentProcessor processor);
    
  2. 该方法参数表示的ComponentProcessor对象,表示需要通过DI(依赖注入)方式实例化该对象中使用Inject修饰的变量:

     @Inject
     InjectBindingRegistry injectBindingRegistry;
     @Inject
     SourceFileGenerator<ProvisionBinding> factoryGenerator;
     @Inject
     SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator;
     @Inject
     ImmutableList<XProcessingStep> processingSteps;
     @Inject
     ValidationBindingGraphPlugins validationBindingGraphPlugins;
     @Inject
     ExternalBindingGraphPlugins externalBindingGraphPlugins;
     @Inject
     Set<ClearableCache> clearableCaches;
    
  • 注:e.g.这里@Inject修饰的InjectBindingRegistry和ValidationBindingGraphPlugins分别以该类型作为type生成key钥匙对象,拿着该钥匙去匹配
  1. 这些变量的实例化有的来自module节点;有的来自于该变量的对象直接使用Inject修饰的构造函数:
  • (1)module节点一定是存在于component节点使用的componentAnnotation#modules及其下面关联的module节点,例如InjectBindingRegistry的实例化关联的是InjectBindingRegistryModule的injectBindingRegistry方法:

     	@Module
     	public interface InjectBindingRegistryModule {
     	    @Binds InjectBindingRegistry injectBindingRegistry(InjectBindingRegistryImpl impl);
     	}
    
  • @Inject修饰的InjectBindingRegistry生成的key钥匙匹配上@Binds修饰的injectBindingRegistry方法

  • (2)ValidationBindingGraphPlugins使用Inject修饰的构造函数:

      	@Inject
         ValidationBindingGraphPlugins(
                 @Validation ImmutableSet<BindingGraphPlugin> plugins,
                 DiagnosticReporterFactory diagnosticReporterFactory,
                 XFiler filer,
                 DaggerTypes types,
                 DaggerElements elements,
                 CompilerOptions compilerOptions,
                 @ProcessingOptions Map<String, String> processingOptions) {
             this.plugins = plugins;
             this.diagnosticReporterFactory = diagnosticReporterFactory;
             this.filer = filer;
             this.types = types;
             this.elements = elements;
             this.compilerOptions = compilerOptions;
             this.processingOptions = processingOptions;
         }
    
  • @Inject修饰的ValidationBindingGraphPlugins生成的key钥匙匹配上使用ValidationBindingGraphPlugins类Inject修饰的构造函数;

  1. 那么@Binds修饰的injectBindingRegistry方法的依赖对象的key和ValidationBindingGraphPlugins类Inject修饰的构造函数的依赖对象的key又会去匹配,直到都得到满意的答复为止。

Resolved解析的意义在于此,让key钥匙匹配到对象,然后该对象的依赖的key又匹配,直到完成。

以上匹配的对象都会响应的收集,并且最终生成一个BindingGraph有向图

Resolved解析器

具体实现查看BindingGraphFactory.createLegacyBindingGraph方法。

整理Resolved解析器首先看下该解析器收集的属性,在从component入口方法解析,然后生成LegacyBindingGraph对象,然后生成...直到BindingGraph,我尼玛看的x都疼,反正这一块除了Resolved比较经典,其他的提升空间非常大。

如何提升?我靠,我要是会...咳咳~当然是如此如此,这般这般啦!!!

写到这里缺乏掌声,好孤独,自己给自己来一个:

Resolved属性赋值

  1. Optional parentResolver:当前解析的subcomponent节点的父级component节点信息解析成resolver对象; subcomponent节点来源:①componentMethod方法返回类型是subcomponent或subcomponent.creator; ②component节点关联的所有subcomponent节点,并且该节点必须被使用了(解析的时候被其他key钥匙不小心匹配上了);

  2. ComponentDescriptor componentDescriptor:当前component节点描述类(或者module节点生成component描述类);

  3. ImmutableSetMultimap<Key, ContributionBinding> explicitBindings:这里是一个Map<K,V>,K表示V的key属性,V来源复杂:

  • (1) 如果是component节点(非module),当前component节点生成的ProvisionBinding绑定对象,属性如下

  • ① contributionType(ContributionType.UNIQUE);

  • ② bindingElement(component节点);

  • ③ Key key: component节点作为type生成的key对象;

  • ④ kind(COMPONENT);

  • (2) componentAnnotation#dependencies中的dependency节点生成ProvisionBinding对象,属性如下:

  • ① contributionType(ContributionType.UNIQUE);

  • ② bindingElement(dependency节点);

  • ③ Key key:dependency节点作为type生成的key对象;

  • ④ kind(COMPONENT_DEPENDENCY);

  • (3)componentAnnotation#dependencies中的dependency节点中无参 && 返回类型不是void的方法生成绑定对象,当前dependency所在component如果使用的是ProductionComponent注解生成的是ProductionBinding对象,否则Component注解生成ProvisionBinding对象,属性如下:

  • ① contributionType(ContributionType.UNIQUE);

  • ② bindingElement(dependency当前无参返回类型不是void的方法节点);

  • ③ Key key:①qualifier,当前方法Qualifier修饰的注解修饰情况;②type:a.当前返回类型如果是ListenableFuture或 FluentFuture将T作为type;b.直接使用方法返回类型作为type;

  • ④ kind(ProductionBinding对象是COMPONENT_PRODUCTION 或 ProvisionBinding对象的COMPONENT_PROVISION);

  • ⑤scope:针对ProvisionBinding,当前Scope注解修饰的注解修饰当前方法情况;

  • ⑥thrownTypes:针对ProductionBinding,当前方法异常抛出情况;

  • (4)component.creator中被@BindsInstance修饰过的方法或方法参数,该方法参数(方法参数根据RequestKind剥离外层框架) ,生成ProvisionBinding对象,属性如下:

  • ① contributionType(ContributionType.UNIQUE);

  • ② bindingElement(@BindsInstance修饰过(或方法参数所在)的方法节点);

  • ③ Key key:方法上的参数类型(根据RequestKind剥离外壳)作为type生成的key;

  • ④ kind(BOUND_INSTANCE);

  • (5)如果当前component节点方法返回类型是一个childcomponent.creator(Builder),并且childcomponent不在 componentAnnotation#modules以及关联的moduleAnnotation#subcomponents的集合中,生成ProvisionBinding对象属性:

  • ① contributionType(ContributionType.UNIQUE);

  • ② bindingElement(childcomponent节点返回类型是subcomponent.builder的方法节点);

  • ③ Key key:当前方法返回类型作为type;

  • ④ kind(SUBCOMPONENT_CREATOR);

  • (6) component关联的module类使用Provides或Produces修饰的方法生成ContributionBinding;

  1. ImmutableSet explicitBindingsSet:表示属性3的V;

  2. ImmutableSetMultimap<Key, ContributionBinding> explicitMultibindings:component关联的module中使用@Provides或@Produces修饰的bindingMethod也是使用了@IntoMap,@IntoSet,@ElementsIntoSet修饰;

  3. ImmutableSetMultimap<Key, MultibindingDeclaration> multibindingDeclarations:component关联的module类使用Multibinds修饰的bindingMethod方法生成MultibindingDeclaration对象;

  4. ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponentDeclarations: component关联的module类的注解moduleAnnotation#subcomponents()里面的类生成的SubcomponentDeclaration;

  5. ImmutableSetMultimap<Key, DelegateDeclaration> delegateDeclarations:component关联的module类使用 Binds修饰的方法生成的DelegateDeclaration;

  6. ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindingDeclarations: component关联的module类使用BindsOptionalOf修饰的bindingMethod生成的OptionalBindingDeclaration;

  7. ImmutableSetMultimap<Key, DelegateDeclaration> delegateMultibindingDeclarations:属性8中的Binds绑定并且使用 @IntoMap,@IntoSet,@ElementsIntoSet注解修饰的绑定方法;

  8. final Queue subcomponentsToResolve = new ArrayDeque<>():当前component关联的收集subcomponent节点,来源:①componentMethod返回类型是subcomponent或subcomponent.creator的subcomponent; ②component关联的module moduleAnnotation#subcomponents()里面的类生成的SubcomponentDeclaration被key要是匹配上了;

以下是通过解析收集到的信息:

  1. Map<Key, ResolvedBindings> resolvedMembersInjectionBindings = new LinkedHashMap<>():K:componentMethod方法有且仅有的一个参数作为type生成的key钥匙;V:ResolvedBindings对象 - ①Key属性就是K;②allMembersInjectionBindings属性:当前参数类型生成MembersInjectionBinding对象;
  • (1)componentMethod方法有且仅有一个参数,返回类型是void或者返回类型和参数类型一致;并且该方法非private、非static修饰;

  • (2)该参数生成的MembersInjectionBinding对象还会注册到InjectBindingRegistryImpl,并且当前参数类型深入遍历非Object对象都生成MembersInjectionBinding对象并且注册到InjectBindingRegistryImpl;

  1. Map<Key, ResolvedBindings> resolvedContributionBindings = new LinkedHashMap<>(): K:这里的key一定被解析的依赖的key属性;V:被解析的依赖的key去匹配声明对象的key属性;
  • 注:打个比方,一个使用@Provides修饰的bindingMethod方法,当前方法生成了ProvisionBinding声明对象,ProvisionBinding声明对象的key属性是和该方法返回类型有关的,ProvisionBinding声明对象的依赖的key是和该方法参数有关的。

Resolved解析

理所当然先上图:

请添加图片描述

同样的可以通过www.iodraw.com/diagram/Resolved解析器图解拖进去查看解析过程

我们来整理一下Resolved解析器代码:

  1. 从componentMethod入口方法开始解析,该非private,非static修饰的方法对该方法依赖的key解析:
  • 入口方法:返回类型不是subcomponent节点的方法;

  • 如果componentMethod方法返回类型是subcomponent节点,不存在依赖,所以不会被解析;

  • 入口方法如果是MEMBERS_INJECTION类型(参数有且仅有一个,表示返回类型和参数类型一致,或返回类型是void,这里为什么返回类型不是creator节点?因为如果返回类型是creator,那么当前方法无参),那么调用resolveMembersInjection方法;否则,调用resolve-后面会讲到。

  1. resolveMembersInjection方法: componentMethod方法的依赖如果是MEMBERS_INJECTION类型,对该依赖的key生成一个MembersInjectionBinding对象(被InjectBindingRegistryImpl收集)并且将该MembersInjectionBinding对象转换成forMembersInjectionBinding类型的ResolvedBindings对象;
  • 生成的ResolvedBindings对象交给resolveDependencies方法处理;

  • 当前forMembersInjectionBinding类型的ResolvedBindings对象被Resolved对象的resolvedMembersInjectionBindings属性收集;

  1. resolveDependencies方法:遍历ResolvedBindings对象的MembersInjectionBinding对象(优先找该对象)或ContributionBinding对象的依赖,将该依赖的key对象交给resolve方法处理;
  • MembersInjectionBinding对象:自行查看多种类型查询总结关系图;

  • ContributionBinding对象:多种类型查询总结关系图中的ProvisionBinding和ProductionBinding对象;

  1. resolve方法:(1)调用lookUpBindings方法将当前key匹配到的ResolvedBindings对象收集与Resolved对象的resolvedContributionBindings中;(2)被key匹配的ResolvedBindings对象执行步骤3 - resolveDependencies方法,对它的key在深入遍历;

  2. lookUpBindings方法:(1)key或key编译匹配不同Binding绑定;如果匹配不成功,去找该key的type类是否使用了Inject或AssistedInject修饰的构造函数,有生成ProvisionBinding对象;(2)对(1)生成的Binding对象生成forContributionBindings类型的ResolvedBindings对象;收集匹配到的Binding对象,思路如下:

  • (1)key去匹配

  • ①当前component节点生成的ProvisionBinding绑定对象;

  • ②componentAnnotation#dependencies中的dependency生成ProvisionBinding对象;

  • ③componentAnnotation#dependencies中的dependency节点中无参返回类型不是void的方法生成ContributionBinding对象;

  • ④component.creator中被@BindsInstance修饰过的方法或方法参数,该方法参数(方法参数根据RequestKind剥离外层框架),生成ProvisionBinding对象;

  • ⑤如果当前component节点方法返回类型是一个childcomponent.creator(Builder),并且childcomponent不在component关联的subcomponent中,对该childcomponent生成ProvisionBinding对象;

  • ⑥component关联的module类使用Provides或Produces修饰的方法生成ContributionBinding;

  • ⑦ @Binds修饰的bindingMethod生成的DelegateDeclaration;

  • (2)key及其变异去匹配

  • ① @Produces或@Provides或@Binds修饰并且也是用@IntoSet或@IntoMap或@ElementIntoSet修饰的bindingMethod;或@Multibinding修饰的BindingMethod;

  • ②在component节点关联的module - moduleAnnotation#subcomponent的subcomponent节点生成的SubcomponentDeclaration对象;

  • (3)key及其变异如果type是Optinal< T>,那么对T作为type生成新的newType,该newType去匹配@BindsOptionalOf修饰的BindingMethod方法;

  • (4)如果key的type是MembersInjector< T>,当前T作为type生成的key去生成一个MembersInjectionBinding并且注册到InjectBindingRegistryImpl中,并且该MembersInjectionBinding对象转换成ProvisionBinding对象被当前方法收集;

  • (5)如果当前key的type类型使用了AssistedFactory注解修饰,对当前type上存在的唯一方法生成ProvisionBinding对象,并且被当前方法收集;

  • (6)如果如果key对以上都没有匹配上,那么对当前key的type是否存在Inject或AssistedInject修饰的构造函数,存在表示匹配上了Inject或AssistedInject修饰的构造函数;

  • 以上收集到的Binding绑定集合生成forContributionBindings类型ResolvedBindings对象,该对象的依赖的key继续匹配...

注:代码的核心逻辑我给整理出来了,具体注解我也写了出来,但是理解还需要认真琢磨!

###ResolvedBindings对象 ###

收集到的信息如下:

  1. Key key:用于匹配的key;

  2. ImmutableMap<TypeElement, MembersInjectionBinding> allMembersInjectionBindings:如果componentMethod(返回类型是void或者与参数类型一致,有且仅有一个)的参数作为type生成的,那么这里的K:当前component节点,V:该参数生成MembersInjectionBinding;

  • 参数生成MembersInjectionBinding注册到InjectRegistryImpl对象中;
  1. ImmutableSetMultimap<TypeElement, ContributionBinding> allContributionBindings:key及其变异匹配的Binding对象,Binding对象如上已给说明;

  2. ImmutableSet multibindingDeclarations:key及其变异 去匹配component节点关联的@Multibinds修饰的bindingMethod方法的生成的MultibindingDeclaration的key;

  3. ImmutableSet subcomponentDeclarations:key及其变异去匹配component关联的module类的注解moduleAnnotation#subcomponents()里面的类生成的SubcomponentDeclaration的key;

  4. ImmutableSet optionalBindingDeclarations: key及其变异如果type是optional类型,那么将T作为type(其他属性都不要了)生成新的key去匹配component关联的@BindsOptionalOf修饰的bindingMethod方法OptionalBindingDeclaration的key属性;

  5. Set multibindingContributions:key及其变异去匹配component关联:①使用@Provides或@Produces修饰的bindingMethod也是使用了@IntoMap,@IntoSet,@ElementsIntoSet修饰的bindingMethod的key;②如果key及其变异的type不是Map类型 || Map(而不是Map<K,V>) ||Map<K,framework>,framework是Produced、Producer、Provider、Lazy、MembersInjector,如果是Map<K,framework>,那么对Map<K,T>作为type生成新的key进行匹配: Binds绑定筛选出还使用@IntoMap,@IntoSet,@ElementsIntoSet注解修饰的绑定方法的key,该DelegateDeclaration转换绑定对象。

总结

可在QQ群:575306647 讨论

源码解析github地址