前言
继续前面的讲解,这里主要是讲解BindingGraph的生成和校验。如果前面的知识点熟透了,这里其实和后面代码的生成部分并不是很难。
绑定图形生成
BindingGraph绑定图形是通过一系列转换最终得到该对象。
LegacyBindingGraph
LegacyBindingGraph对象主要是从componentMethod入口方法(入口方法存在依赖,所以返回类型不能是subcomponent节点)为切入点,从componentMethod入口方法的依赖的key开始去匹配各种声明的key属性:
名词解释:各种声明有 —— Binding绑定声明、SubcomponentDeclaration声明、MultibindingDeclaration声明、OptionalBindingDeclaration声明、DelegateDeclaration声明;
-
如果componentMethod方法有唯一param参数,返回类型是void或者返回类型和param参数类型一致:当前param参数生成一个MembersInjectionBinding对象,并且注册到InjectRegistryImpl中;并且将当前param类使用Inject修饰的变量或普通方法生成的依赖对象的key属性去全局匹配当前component关联的各种声明对象的key属性;
-
如果componentMethod方法无参:当前方法生成的依赖的key属性去全局匹配当前component关联的各种声明对象的key属性;
-
除了匹配还收集:(1)依赖的key的type如果是MembersInjector类型,对T作为type生成的key生成MembersInjectionBinding(注册到InjectRegistryImpl中),转换成ProvisionBinding对象被收集;(2)如果依赖的key的type使用了AssistedFactory注解;
-
并且依赖的key属性都没有匹配上,那么判断当前依赖的key的type类型是否存在Inject或AssistedInject修饰的,如果存在生成ProvisionBinding(注册到InjectRegistryImpl中)。
属性如下:
-
ComponentDescriptor componentDescriptor:component节点生成的描述对象;
-
ImmutableMap<Key, ResolvedBindings> contributionBindings:Resolver对象的resolvedContributionBindings集合——componentMethod方法为切入点,所有被componentMethod方法的依赖的key关联的各种声明的key,并且如果声明的key不是ContributionBinding对象(如SubcomponentDeclaration声明、MultibindingDeclaration声明、OptionalBindingDeclaration声明、DelegateDeclaration声明)那么转换成ContributionBinding对象;
- 依赖的key去匹配声明的key,声明的依赖的key再去匹配component节点关联的其他声明的key,反复匹配。
-
ImmutableMap<Key, ResolvedBindings> membersInjectionBindings:Resolver对象的resolvedMembersInjectionBindings集合——仅仅收集componentMethod有且仅有一个param参数,该参数生成MembersInjectionBinding,该参数生成MembersInjectionBinding对象生成的forMembersInjectionBinding类型的ResolvedBindings;
-
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节点,属性如下:
-
ComponentPath componentPath:收集当前currentcomponent节点直到rootcomponent节点;
-
ComponentDescriptor componentDescriptor:当前正在处理的currentcomponent节点生成的componentDescriptor对象;
-
isSubcomponent:当前currentcomponent节点是否是subcomponent;
-
isRealComponent:currentcomponent节点是否真的component节点(module节点也可以转换成component对象);
ResolvedBindingsWithPath
该对象存在的意义是,当前currentComponent节点的依赖的key匹配到的关联的声明对象生成的ResolvedBindings对象;
-
ResolvedBindings resolvedBindings:被key钥匙匹配上的各种声明生成的ResolvedBindings对象;
-
ComponentPath componentPath:存储当前正在处理的currentComponent节点;
BindingNode绑定节点
绑定Node节点,绑定节点属性如下:
-
ComponentPath componentPath:当前currentcomponent节点直到rootcomponent节点被收集与ComponentPath对象;
-
dagger.internal.codegen.binding.Binding delegate:被钥匙key匹配上的绑定Binding(的key属性)对象;
-
ImmutableSet multibindingDeclarations:被钥匙key属性匹配上的multibinds修饰的MultibindingDeclaration声明对象;
-
ImmutableSet optionalBindingDeclarations:被钥匙key属性匹配上的OptionalBindingDeclaration声明对象;
-
ImmutableSet subcomponentDeclarations:被钥匙key属性匹配上的SubcomponentDeclaration声明对象;
DependencyEdgeImpl边
源头Node节点指向一个指向Node节点的edge边,属性如下:
-
DependencyRequest dependencyRequest:入口方法或各种声明的依赖;
-
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节点生成
对以上对象有个理解再来看有向图生成,逻辑如下:
- 正在处理的currentComponent节点,先添加一个ComponentNodeImpl节点;
- ComponentNodeImpl存储了①当前currentComponent节点生成的描述类和②当前currentComponent节点及其直到rootcomponent节点收集在ComponentPath对象中;
- 访问当前正在处理的component节点入口方法(非private、非static、abstract修饰的抽象方法或接口方法):即方法存在依赖,即方法返回类型不是subcomponent节点那么该方法就存在依赖:
-
(1) 当前componentMethod方法的依赖的key钥匙匹配LegacyBindingGraph的membersInjectionBindings属性(优先)和contributionBindings属性:
-
①当前ResolvedBindings的Binding对象(如果allMembersInjectionBindings不为空则使用该属性,否则使用allContributionBindings)生成BindingNode绑定节点;
-
② 生成一条由componentNodeImpl源头节点指向①中生成的指向BindingNode绑定节点的DependencyEdgeImpl依赖边;
- 对当前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边;
-
如果当前处理的LegacyBindingGraph对象subgraphs(即子LegacyBindingGraph),并且其父级LegacyBindingGraph表示的component节点存在componentMethod方法返回类型是subcomponent节点的(非private、非static、abstract修饰的抽象方法(或接口方法))表示的就是当前子LegacyBindingGraph中的component节点;对当前父级componentNode源头节点指向当前component生成的ComponentNode节点生成一条ChildFactoryMethodEdgeImpl边;
-
访问当前LegacyBindingGraph的subgraphs,即从步骤1指向子LegacyBindingGraph;
BindingGraph.TopLevelBindingGraph
转换成BindingGraph前的一道工序:
-
ImmutableNetwork<Node, Edge> network:上面生成的MutableNetwork对象
-
boolean isFullBindingGraph:传递的参数;
-
ImmutableMap<ComponentPath, ComponentNode> componentNodes:所有component或subcomponent生成的componentNode节点;
-
ImmutableSetMultimap<ComponentNode, ComponentNode> subcomponentNodes:当前component关联的subcomponent生成的componentNode节点,排除了rootcomponent节点;
BindingGraph
最终生成了BindingGraph,属性如下:
-
dagger.spi.model.BindingGraph.ComponentNode componentNode:当前currentcompoent节点生成的ComponentNode节点;
-
BindingGraph.TopLevelBindingGraph topLevelBindingGraph:以上生成的TopLevelBindingGraph对象;
-
ImmutableMap<Key, BindingNode> contributionBindings:当前有向图的BindingNode节点中所有的ContributionBinding类型的绑定对象;
-
ImmutableMap<Key, BindingNode> membersInjectionBindings:当前有向图的BindingNode节点中所有的MembersInjectionBinding类型的绑定对象;
-
ImmutableSet inheritedModules:当前BindingGraph的父级BindingGraph中处理的componentAll节点关联的module节点和componentAll节点关联的subcomponent节点关联的module节点;
-
ImmutableSet ownedModules:当前ComponentNode节点表示的componentAll关联的所有module节点(排除componentAll节点关联的subcomponent中关联的module节点)生成的ModuleDescriptor对象;
-
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 讨论