7.Dagger2.38.1源码解析-BindingGraph绑定图形生成和校验

前言

继续前面的讲解,这里主要是讲解BindingGraph的生成和校验。如果前面的知识点熟透了,这里其实和后面代码的生成部分并不是很难。

绑定图形生成

BindingGraph绑定图形是通过一系列转换最终得到该对象。

LegacyBindingGraph

LegacyBindingGraph对象主要是从componentMethod入口方法(入口方法存在依赖,所以返回类型不能是subcomponent节点)为切入点,从componentMethod入口方法的依赖的key开始去匹配各种声明的key属性:

名词解释:各种声明有 —— Binding绑定声明、SubcomponentDeclaration声明、MultibindingDeclaration声明、OptionalBindingDeclaration声明、DelegateDeclaration声明;

  1. 如果componentMethod方法有唯一param参数,返回类型是void或者返回类型和param参数类型一致:当前param参数生成一个MembersInjectionBinding对象,并且注册到InjectRegistryImpl中;并且将当前param类使用Inject修饰的变量或普通方法生成的依赖对象的key属性去全局匹配当前component关联的各种声明对象的key属性;

  2. 如果componentMethod方法无参:当前方法生成的依赖的key属性去全局匹配当前component关联的各种声明对象的key属性;

  3. 除了匹配还收集:(1)依赖的key的type如果是MembersInjector类型,对T作为type生成的key生成MembersInjectionBinding(注册到InjectRegistryImpl中),转换成ProvisionBinding对象被收集;(2)如果依赖的key的type使用了AssistedFactory注解;

  4. 并且依赖的key属性都没有匹配上,那么判断当前依赖的key的type类型是否存在Inject或AssistedInject修饰的,如果存在生成ProvisionBinding(注册到InjectRegistryImpl中)。

属性如下:

  1. ComponentDescriptor componentDescriptor:component节点生成的描述对象;

  2. ImmutableMap<Key, ResolvedBindings> contributionBindings:Resolver对象的resolvedContributionBindings集合——componentMethod方法为切入点,所有被componentMethod方法的依赖的key关联的各种声明的key,并且如果声明的key不是ContributionBinding对象(如SubcomponentDeclaration声明、MultibindingDeclaration声明、OptionalBindingDeclaration声明、DelegateDeclaration声明)那么转换成ContributionBinding对象;

  • 依赖的key去匹配声明的key,声明的依赖的key再去匹配component节点关联的其他声明的key,反复匹配。
  1. ImmutableMap<Key, ResolvedBindings> membersInjectionBindings:Resolver对象的resolvedMembersInjectionBindings集合——仅仅收集componentMethod有且仅有一个param参数,该参数生成MembersInjectionBinding,该参数生成MembersInjectionBinding对象生成的forMembersInjectionBinding类型的ResolvedBindings;

  2. ImmutableList subgraphs:subcomponent节点生成LegacyBindingGraph对象,subcomponent来源:①componentMethod方法返回类型是subcomponent或subcomponent.builder表示的subcomponent节点;②component关联的module moduleAnnotation#subcomponents()里面的subcomponent节点生成的SubcomponentDeclaration,该subcomponent节点只有在被key及其变异匹配上了才可以;

生成由edge有向边和Node节点组成的有向图MutableNetwork

用于解析上面得到的LegacyBindingGraph对象。

在介绍MutableNetwork有向边和节点生成生成前先对几个对象了解下

ComponentPath对象

存储component节点:(1)如果是一个rootcomponent节点,那么就收集当前rootcomponent节点;(2)如果是一个subcomponent节点,那么收集的是该subcomponent节点所在的父级component节点(直到该父级component节点是rootcomponent节点)和当前subcomponent节点;

  • subcomponent节点来源(1)componentMethod返回类型是subcomponent或subcomponent.creator;(2)component关联(componentAnnotation#modules的module,moduleAnnotation#subcomponents)的subcomponent节点;

ComponentNodeImpl节点:有向图节点

component节点会生成有向图Node节点,属性如下:

  1. ComponentPath componentPath:收集当前currentcomponent节点直到rootcomponent节点;

  2. ComponentDescriptor componentDescriptor:当前正在处理的currentcomponent节点生成的componentDescriptor对象;

  3. isSubcomponent:当前currentcomponent节点是否是subcomponent;

  4. isRealComponent:currentcomponent节点是否真的component节点(module节点也可以转换成component对象);

ResolvedBindingsWithPath

该对象存在的意义是,当前currentComponent节点的依赖的key匹配到的关联的声明对象生成的ResolvedBindings对象;

  1. ResolvedBindings resolvedBindings:被key钥匙匹配上的各种声明生成的ResolvedBindings对象;

  2. ComponentPath componentPath:存储当前正在处理的currentComponent节点;

BindingNode绑定节点

绑定Node节点,绑定节点属性如下:

  1. ComponentPath componentPath:当前currentcomponent节点直到rootcomponent节点被收集与ComponentPath对象;

  2. dagger.internal.codegen.binding.Binding delegate:被钥匙key匹配上的绑定Binding(的key属性)对象;

  3. ImmutableSet multibindingDeclarations:被钥匙key属性匹配上的multibinds修饰的MultibindingDeclaration声明对象;

  4. ImmutableSet optionalBindingDeclarations:被钥匙key属性匹配上的OptionalBindingDeclaration声明对象;

  5. ImmutableSet subcomponentDeclarations:被钥匙key属性匹配上的SubcomponentDeclaration声明对象;

DependencyEdgeImpl边

源头Node节点指向一个指向Node节点的edge边,属性如下:

  1. DependencyRequest dependencyRequest:入口方法或各种声明的依赖;

  2. boolean entryPoint:如果源头节点是ComponentNode节点,则表示是入口——true;

SubcomponentCreatorBindingEdgeImpl

属性就一个ImmutableSet subcomponentDeclarations:被钥匙key匹配上的所有的SubcomponentDeclaration声明对象

该匹配的SubcomponentDeclaration声明对象当然存在于ResolvedBindings对象中

依赖的key当然是匹配SubcomponentDeclaration声明对象的key属性;

ChildFactoryMethodEdgeImpl

DaggerExecutableElement factoryMethod:component节点的componentMethod方法,该方法返回类型是subcomponent节点。

这条边的源头节点是component生成的Node节点,指向的节点是subcomponent生成的Node节点;

MutableNetwork edge有向边和node节点生成

对以上对象有个理解再来看有向图生成,逻辑如下:

  1. 正在处理的currentComponent节点,先添加一个ComponentNodeImpl节点
  • ComponentNodeImpl存储了①当前currentComponent节点生成的描述类和②当前currentComponent节点及其直到rootcomponent节点收集在ComponentPath对象中;
  1. 访问当前正在处理的component节点入口方法(非private、非static、abstract修饰的抽象方法或接口方法):即方法存在依赖,即方法返回类型不是subcomponent节点那么该方法就存在依赖:
  • (1) 当前componentMethod方法的依赖的key钥匙匹配LegacyBindingGraph的membersInjectionBindings属性(优先)和contributionBindings属性:

  • 当前ResolvedBindings的Binding对象(如果allMembersInjectionBindings不为空则使用该属性,否则使用allContributionBindings)生成BindingNode绑定节点;

  • 生成一条由componentNodeImpl源头节点指向①中生成的指向BindingNode绑定节点的DependencyEdgeImpl依赖边

  1. 对当前LegacyBindingGraph对象membersInjectionBindings和contributionBindings合并的ResolvedBindings对象遍历:
  • 注:该ResolvedBindings对象是对componentMethod入口依赖的key的一步步匹配得到的所有绑定对象,依赖的key钥匙匹配声明的key目的在于依赖的key的实例化参数需要声明的key提供支持

  • (1)当前ResolvedBindings的Binding对象(如果allMembersInjectionBindings不为空则使用该属性,否则使用allContributionBindings)生成BindingNode绑定节点;

  • (2)该BindingNode节点的依赖集合遍历:

  • 注:BindingNode节点的依赖 —— 依赖的key匹配上的Binding绑定对象,该Binding绑定对象的依赖;

  • ① 查找当前Binding绑定对象的依赖的key匹配到的component各种声明(ResolvedBindings对象);

  • 当前ResolvedBindings的Binding对象(如果allMembersInjectionBindings不为空则使用该属性,否则使用allContributionBindings)生成BindingNode绑定节点;

  • 生成一条由绑定源头节点指向绑定指向节点的DependencyEdgeImpl边

  • (3)操作(1)过程中,如果存在Binding声明对象的kind是SUBCOMPONENT_CREATOR类型,表示依赖的key关联上的是component关联的subcomponent节点,所以这里添加一条绑定为源头的节点指向subcomponentNode节点的SubcomponentCreatorBindingEdgeImpl边

  1. 如果当前处理的LegacyBindingGraph对象subgraphs(即子LegacyBindingGraph),并且其父级LegacyBindingGraph表示的component节点存在componentMethod方法返回类型是subcomponent节点的(非private、非static、abstract修饰的抽象方法(或接口方法))表示的就是当前子LegacyBindingGraph中的component节点;对当前父级componentNode源头节点指向当前component生成的ComponentNode节点生成一条ChildFactoryMethodEdgeImpl边

  2. 访问当前LegacyBindingGraph的subgraphs,即从步骤1指向子LegacyBindingGraph;

BindingGraph.TopLevelBindingGraph

转换成BindingGraph前的一道工序:

  1. ImmutableNetwork<Node, Edge> network:上面生成的MutableNetwork对象

  2. boolean isFullBindingGraph:传递的参数;

  3. ImmutableMap<ComponentPath, ComponentNode> componentNodes:所有component或subcomponent生成的componentNode节点;

  4. ImmutableSetMultimap<ComponentNode, ComponentNode> subcomponentNodes:当前component关联的subcomponent生成的componentNode节点,排除了rootcomponent节点;

BindingGraph

最终生成了BindingGraph,属性如下:

  1. dagger.spi.model.BindingGraph.ComponentNode componentNode:当前currentcompoent节点生成的ComponentNode节点;

  2. BindingGraph.TopLevelBindingGraph topLevelBindingGraph:以上生成的TopLevelBindingGraph对象;

  3. ImmutableMap<Key, BindingNode> contributionBindings:当前有向图的BindingNode节点中所有的ContributionBinding类型的绑定对象;

  4. ImmutableMap<Key, BindingNode> membersInjectionBindings:当前有向图的BindingNode节点中所有的MembersInjectionBinding类型的绑定对象;

  5. ImmutableSet inheritedModules:当前BindingGraph的父级BindingGraph中处理的componentAll节点关联的module节点和componentAll节点关联的subcomponent节点关联的module节点;

  6. ImmutableSet ownedModules:当前ComponentNode节点表示的componentAll关联的所有module节点(排除componentAll节点关联的subcomponent中关联的module节点)生成的ModuleDescriptor对象;

  7. ImmutableSet bindingModules:当前有向图的BindingNode节点中所有的ContributionBinding类型的绑定对象如果能找到所在module节点,那么进行收集。

写到这里略显失望,感觉和Resolved解析器作用重叠(稍加改动直接使用有向图它不香吗!!!),Resolved整体来看还是非常精彩的。哎!这就像电影,这个算是电影的瑕疵。后面代码生成的部分我感觉还是有看头的,俄罗斯套娃模式,在此打一顿比方。

BindingGraph校验

执行ComponentProcessingStep的validateFullBindingGraph方法,在BindingGraphValidator类的isValid方法完成校验。

这里ExternalBindingGraphPlugins看不了,本身就存在一个bug。我们直接看ValidationBindingGraphPlugins校验,visit方法表示校验入口。

BindingGraphValidationModule的providePlugins方法收集针对不同绑定图形插件的校验,具体校验如下:

DependencyCycleValidator

校验生成的有向图不能存在如下循环的情况,只能是单方向的。

DependsOnProductionExecutorValidator

如果使用了Produces注解,完成当前校验:

如果BindingGraph中的有向图中的MaybeBinding节点的key是Executor作为type和Production作为qualifier属性生成的key,那么当前MaybeBinding节点中的Binding对象的key属性必须是Executor作为type和ProductionImplementation作为qualifier;

DuplicateBindingsValidator

被key匹配上的所有的Binding对象,不允许出现Binding对象的key属性相同的情况。

IncompatiblyScopedBindingsValidator

有向图上所有的Node节点是Binding的情况,并且使用了(Reusable除外)Scope注解修饰的注解修饰,那么当前Binding所属component必须也是用该Scope注解修饰(除非当前 Binding是Inject修饰的构造函数生成的 && (当前绑定有向图的rootComponent是subcomponent || 当前绑定有向图的rootComponent是module节点));

InjectBindingValidator

有向图上的被Inject修饰的构造函数生成的Binding对象,对该构造函数所在父类的变量和普通方法以及构造函数校验(前面已经介绍过了,这里不多做介绍)。

MapMultibindingValidator

key如果是Map<K, X>,找出该key匹配到的所有Binding绑定类型,有Map<K, V>,Map<K, Provider>,Map<K, Producer>。

当前相同的Map<K,X>类型的key不允许出现超过1个;

当前相同的@MapKey修饰的注解也不允许出现超过1个;

MissingBindingValidator

当前有向图的root component node节点如果不是subcomponent,那么进行下面判断,当前有向图不应该存在MissBinding node节点,否则会报错。

NullableBindingValidator

如果有向图上的Binding绑定节点是允许null的,但是Binding绑定node节点关联的边的依赖属性不允许null,将会报错。

ProvisionDependencyOnProducerBindingValidator

BindingGraph有向图上的production类型的Binding绑定对象,该Binding绑定node节点关联的边,该边的是入口边(依赖的requestKind是PRODUCER、PRODUCED或FUTURE)或该边的源头node节点是prodoction类型则没问题,否则将报错。

SetMultibindingValidator

BindingGraph有向图上的key是set< T>的Binding对象,那么该Binding对象通过有向边能达到的TargetBinding对象如果@Binds类型,那么该TargetBinding对象最多只能存在一个;

SubcomponentFactoryMethodValidator

当前BindingGraph有向图的rootComponent如果是module节点或是subcomponent节点,那么不进行下面的校验;

收集BindingGraph所有的ChildFactoryMethodEdge边:表示component节点中的返回类型是subcomponent节点的componentMethod方法生成的edge边,该edge边的源Node节点是component节点,目标Node节点是subcomponent节点;

对component节点中返回类型是subcomponent的componentMethod方法的module参数校验:

module参数必须存在于subcomponent或component关联的modules集合中,并且modules集合中的item还必须需要实例化。

总结

这里的BindingGraph对象生成,个人感觉应该是整个项目目前来说最混乱也是最应该整合的地方。

可在QQ群:575306647 讨论

源码解析github地址

Supongo que te gusta

Origin juejin.im/post/7067696113993662495
Recomendado
Clasificación