Spring 源码 八(无参构造方法,特殊构造方法如何实例化)

图1-0

图1-1

图1-2

图1-3

图1

图2

 图3

图4

此时的beanFactory是DefalutListableBeanFactory。所以执行这个类的preInterantiateSingletons()方法。 

图5

743行拿出所有的bd名称。

754 行判断是否有父的bd 。如果有父的bd。把父的bd和子的bd进行合并。图6 ,7,8,9,10举例说明。这个不重要,只有在xml中有这种写法。springBoot中已经淘汰了。例如index 不是抽象类,是单例,不是懒加载 会进第一个 if, 但是 index 没有包含& 所以不是 factoryBean .所以会进入下面的else分支中。

 接图11.

图6

图7

图8

图9

图10

打印结果:

 这种子和父关系的orderService 在spring 中是怎么存的?会存两个示例,例如 order 和orderCjil 。这个两个示例的作用域,类名都一样。

作用域和类名是不是和bdmap有关系呢

t图11

图12

 

看上面注释。

那一种情况不为空呢,第二次调用的时候,或者是lazy的时候。 

 

sharredInstance不等于null的情况。

sharredInstance等于null的时候,如果是原型的话报错。判断我们正在创建的类是不是原型的。这段情况一般不会发生的,因为前面有判断是singleon的。  spring 在创建一个bean的时候,会往一个list中放一个beanName ,标识这个类正在创建。有一个属性currentlyInCreation表示正在创建。

 

因为只有我们设置了parentBeanFactory父类的工厂方法才会进这个代码,一般没有不重要。一般情况下是空。

 添加到aleradyCreated的set中标识已经创建了(图16)。不重要。

 

获取bd。校验bd。  bd 中获取依赖dependsOn ,如果有依赖。率先示例化他的依赖。目前index没有依赖。所以为空。

如果是单例的调getSingleton 。index是单例的。所以今日362行  。注意这个getSingLeton和上次那个getSingLeton不一样。图19。 createBean() 图 21

 

图13

图14

图15

图16

图17

图18

图19

 

 

 

图20

 

图20

两个getSingleton() 的区别。 第一个getSingleton()  == null 的时候,还要判断 isSingletonCurrentlyInCreation  判断这个类是不是正在创建,所以返回空。第二个getSingleton() 是经过各种densponsOn验证以后,并在set添加正在创建,如果为空则创建对象。使用new对象。而上一个主要用于beanFactory.getBean()。

图21

通过bd ,得到一个indexService这样的李。不重要。

lookup-menthod 和replace-method ,spring统称为method overriders 

如果在创建bean之前或者初始化之前, 通过执行后置处理器的前置方法,和后置方法如果能返回一个不为空的bean就直接返回,终止后续操作。不在示例化bean,和填充属性了,自动装配。

创建bean 。图 25

 图22

图23

如果你想返回的对象是一个广对象,不需要填充属性等操作,直接返回,就实现这个接口InstantiationAwareBeanPostProcessor

图24

InstantiationAwareBeanPostProcessor 这个类有三个方法,加上继承父类的一共有五个方法,我们可以随便实现那个方法,然后把对象new 出去返回,那么spring就不会做后续的实例化,填充属性的,没有任何依赖操作。主要是spring内部使用的。程序员使用无意义。InstantiationAwareBeanPostProcessor是内部后置处理器。 

图25

538行如果是单例,从factoryBeanInstanceCache,缓存中移除。

 创建bean示例。

获取的instanceWrapper 对象,然后调用他的getWrappedInstance() 方法返回他的bean对象。 

图25-0

new 出来对象以后,首先放在singletonFactories这个map中一个,放registeredSingletons的list中一个。earlySingletonOjbects中移除。

图25-1

填充属性。

图26

 不重要。

工厂方法。举例说明 图

 

由后置处理器决定返回那些构造方法。如果是默认构造方法,spirng 的ctors返回空,默认没有构造方法 走无参构造方法。如果有一个有参的构造方法,ctors就不为空。走特殊构造方法逻辑。那么问题来了。假如 index里既有默认的无参构造器和有参构造器,spring ctors是为空还是不为空呢? 答案是为空。因为这个时候spirng 。 还有装配模型的必须是Autowire_constructor  详细图34。

如果有图40那种外部提供给spring 的构造方法和参数值的情况,下ctors 为1。但是用xml也是灭有值的。

这个是无参的构造法初始化图31。   特殊构造器初始化.图35

图27

IndexService ()方法。如果加了static 会IndexService会创建多次。如果不加会创建一次。为什么呢.图28标红处

图28

 

 

如果是static 设置为factoryMethode。相当于下面的xml形式。

图29

 图30

 

 

lookup 在下次课。

 首先从缓存中拿一个。因为我们没有往这个map中put。所以这个应该为空。

 

273行拿到了一个构造方法。

  拿出构造方法,每次循环一次,nonSyntheticConstructors 加一次。

当前index他的注解为null不会进。

如果拿出的参数等于0的时候 ,让他成为一个默认的构造方法。

 循环完之后判断candidates是不是空。因为没有candidates.add()这个分支没有走,所以为空。

 344行,如果有一个构造器并且构造器的参数的个数大于 0  ,有一个有参数的构造器返回。如果347行如果有两个构造器,并且在xml 设置了primary=true 的时候,defaultConstructor !=null。defaultConstructor 什么时候付的值呢,是在构造参数个数等于0的时候付的值。含有primary属性的构造器 和默认的的构造器的不一样的时候才会使用; 如果有一个默认构造器和一个无参构造如果不配置primary=true 当然也没有办法进这个分支,以下的分支也不成立最后null返回了。所以就用默认的构造器,无参构造器示例化。

如果是默认构造器,不走任何分支,返回空。

图31

jdk校验不重要。

无参构造器实例化。默认采用cglib的反射示例化策略。

图32

图33

 

80行得到默认的构造方法,及时把index 类的 所有构造方法删除,也可以得到这个默认的构造方法。

 实例化对象反射创建完成返回。

图34

pring 自动装配模型有, by_no,by_type,by_name;自动装配技术有@Autowrid @Resource ;spring 默认的自动装配模型是by_no,如果不加@Autowrid @Resource 注解时候,不自动装配。如果加了@Autowrid @Resource 才会自动装配。 如果是自动装配模型是by_type。加不加@Autowrid @Resource 都无所谓,只与set方法有关系,和属性和注解都没有关系。

图35

图36

图37

bw 中有个属性wrappedObject对象用来存储真是的对象。

constructorToUse决定使用哪个构造方法来示例化的对象。 argHolderToUse 构造方法需要哪些参数。

定义一个转化参数的变量argsToResolve. 134获取已经解析的构造方法。如果说这个构造方法已经解析完成,会赋值到resolvedConstructorOrFactoryMethod这个属性中。 他首先从这个属性中获取。如果不等于空从bd中获取参数给argToUser赋值。如果argsToResolve不为空进行解析。

如果传了构造方法,或者指定按自动装配解析。spring就要按构造方法装配.autowiring=true;

定义了构造方法参数值为空的一个局部变量。定义一个最小的参数个数,explicitArgs外面传进来的参数值,如果不为空最小的参数个数就是explicitArgs 的值。目前传过来的explicitArgs为空。

 

 

 

如果有图40那种外部提供给spring 的构造方法和参数值的情况,下ctors 为1

为什么要定义Map和List 两种数据结构来存储呢参数值呢,?list 是用来存储无序的。Map是用来存储有序的。比如上图xml中,Map应该存储为 (0,arg);   外部可以通过标红出的方式传给spring 构造方法和参数值。cags 就是获取这种参数值。

确定构造方法的参数数量。minNrOfArgs 通过cags 获取这些外部值,如果cags有两个值,那么最小的参数值也应该有两个。

如果有图40那种外部提供给spring 的构造方法和参数值的情况,下minNrOfArgs 为1

把所有的构造方法赋值个candidates。不为空跳出

构造方法排序 先根据public 权限排序。再跟据参数个数排序。

定义了一个minTypeDiffWeight 最小类型差异变量 默认设置的是Integer的最大值。ambiguousConstructors 分歧变量。 

如果constructorToUse 不为空,证明 已经找到的合适的构造方法,那为什么不返回呢,因为他还要看下,下面是不是有更合适的构造方法, constructorToUse 不为空,那么argsToUse 参数的个数就是已经拿到的构造器的参数个数大于循环中的构造器参数个数就返回,因为再往下循环参数个数会越来越小,所以就没有必要再往下找了。break出去, 存放构造器这个list已经经过排序,最大的构造参数在上面,这样排序的。

 minNrOfArgs 通过cags 获取这些外部值,如果cags有两个值,那么最小的参数值也应该有两个。所以如果类型个数都小于最小参数个数,肯定要跳出本次循环。

加了@ConstructorProperties注解回去这里面的值,不重要。

这个拿到参数值然后放到paramNames中。

 

这个就是把上图xml中的order字符串类转化成 一个orderService类型。 可以把paramNames中的luban字符串转化成Luban的对象下图。

 

 

minTypeDiffWeight 默认是最大值。  typeDiffWeight 差异值,第一次typeDiffWeight < minTypeDiffWeight 值。

 

ambiguousConstructors存放差异值,如果构造器一样,差异一样 ,会存在 ambiguousConstructors这个种,放在最后抛出异常处理。

如果找到下一个差异值比这个更小,那么就清空ambiguousConstructors =null;

 

constructorToUse肯定不为空。 

 ambiguousConstructors存放差异值 异常处理。为什么找到两个相同的构造器一开始就抛异常,而是要等到遍历结束后统一抛异常处理呢,因为后面循环有可能找到一个更加匹配的。

 

 

 生成策略。

示例化对象。

图38

 

图39

 图40

图41

benaFactory.getBeanDefinition('index')

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值