bean生命周期的基本流程

bean生命周期的基本流程

class(UserService) > 推断构造方法 > 实例化 > 对象(target) > 属性填充 > afterPropertiesSet (初始化) > AOP > 代理对象 > bean

推断构造方法

spring在实例化对象的时候会调用构造方法来实例化对象,如果没有构造方法,那spring就使用默认的无参构造方法来实例化对象。如果有构造方法,又或者有多个不同参数的构造方法,那么spring该如何选择一个构造方法来实例化对象呢。以下几种情况:

  1. 只有一个有参构造方法时
    那肯定就使用这个构造方法,因为Spring没有其他选择了

  2. 有两个有参构造方法时
    在这里插入图片描述此时spring会直接报错,因为参数肯定代表某种意义,现在两个构造方法都有参数,spring不知道该用哪个了,所以直接报错。

  3. 有一个无参构造和两个有参构造方法时
    在这里插入图片描述此时会默认使用无参构造。
    spring在选择构造方法是这样去推断的。那么,如果spring选择用有参的构造方法取实例化对象,那必须得传一个参数。参数怎么来呢,它会去spring容器中去找这个参数的bean。怎样去找呢,通过bytype、byname去找。

  4. bytype: spring通过参数类型找到对应类型的bean,如果只有一个bean,那直接就把这个bean传入参数中。但是也有可能会有多个bean,这里就有同学会疑问了,不是说bean是单例的嘛,怎么会有多个同类型的bean对象。这里就要提到一个概念单例bean
    单例bean: 在这里插入图片描述在这里插入图片描述
    orderService1和orderService2是bean注解自定义的两个bean。orderService是默认的一个bean
    在这里插入图片描述
    分别输出3个bean,可以看出不是一个对象。单例bean其实跟名字有关,是指同一个名字的bean对象是单例的。
    在这里插入图片描述
    可以看出同一个名字的bean无论get多次都是同一个bean对象。那么单例bean的底层到底是怎么实现的呢,通过一个map,map的key就是bean的name,value就是对应的bean对象。把这个map可以称为单例池

  5. byname: 通过bytype找到多个同类型的bean对象,此时就要通过参数的name去判断应该使用哪个bean。
    前面提到的如果用有参构造方法去实例化bean,就是通过bytype和byname去spring容器中找参数对象的。如果bytype可以找到,但是byname没有匹配的名字,就会报错,提示找不到这个bean对象。

属性填充(Autowired和Resource)

  1. @Autowired
    在这里插入图片描述
    在这里插入图片描述
    autowired注解的另一个用法就是告诉spring在有多个构造方法时默认使用autowired注解的构造方法。

下面来看下Autowired普通用法的工作原理,其实也是通过bytype和byname,但是中间会有其他操作。
在这里插入图片描述

通过bytype找到多个bean,然后调用isAutowireCandidate判断是否是自动填充的候选者。我们可以看一下源码
在这里插入图片描述
它默认是true。
在这里插入图片描述
在bean注解里可以给他设置为false。那么设置为false之后呢,那么spring通过bytype查找到的orderService类型的对象就不是3个了,它会过滤掉false的bean。

问题来了,如果这样去注入
在这里插入图片描述
它会把下面的orderService1注入进去对吧,那么如果给orderService1中的bean注解添加(autowireCandidate = false)属性,上面的autowired还会把orderService1注入嘛。答案是不会,会报错。
在这里插入图片描述
因为,spring在找到3个orderService(orderService、orderService1、orderService2)类型的bean后会把设置了autowireCandidate为false属性的bean过滤掉。在剩下的orderService和orderService2中去找对应的bean。接下来会用到Qualifier去过滤,过滤完后再通过byname去找,如果还没有找到就报错。那么@Qualifier这个注解大家都有用到过,是配合@Autowired去使用的。
Qualifier相当于一个分组。例如
在这里插入图片描述
在这里插入图片描述
userService中注入的名称为orderService3这个bean,本身是没有这个名称的bean,但是上面用到了Qualifier这个注解。那么它会直接注入Qualifier属性为order1的bean。如下图这样
在这里插入图片描述
那么最终还是会根据bean的名字去找。没有匹配的名字就报错。
上面提到的通过isAutowireCandidate和Qualifier筛选后都有可能剩多个bean,那么下面通过Primary和优先级就会筛选出一个,因为Primary只能给一个bean加注解。
通过@Primary设置主bean,但是Primary只能设置再类上面。
经过这一系列的筛选最后通过byname去找一个bean注入。

  1. @Resource
    在这里插入图片描述
    可以看到Resource注解是通过先byname、再bytype去注入的。
    如果指定了@Resource(name=“xxx”)name属性,直接去spring容器中去找,没找到就报错。如果没有指定name属性,会进行如下操作
    在这里插入图片描述
    用name去map中判断有没有一个key是orderService3的。如果有一个key为orderService3那么就取出对应的value注入到对象中,假如判断没有一个key为orderService3,那么回去通过orderService类型去找,找到多个还是会报错,如果通过类型只找到一个orderService类型的bean。就会直接注入。这就是为什么@Resource注解是先byname后bytype的原因

  2. afterPropertiesSet(初始化)
    在这里插入图片描述
    通过实现InitializingBean接口重写afterPropertiesSet方法去实现初始化的一些操作。还可以通过@PostConstruct注解去定义一个初始化方法。
    在这里插入图片描述

    AOP

  3. AOP
    在初始化后完后,Spring容器会判断当前这个对象要不要进行AOP。所以Spring容器会找出里面所有的切面的bean。判断有没有对象对应的切点,有就会匹配上放到缓存中,下次来直接生成代理对象。下面是定义的userService切点
    在这里插入图片描述
    接下来看下Spring怎样生成代理对象的,有两种方法
    1.假设目标对象的实现类实现了接口。Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
    2.假设目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类
    对于我们的userService对象来说,是采用CGLIB 来生成 AOP 代理类的。如下模拟生成AOP代理类
    在这里插入图片描述
    定义一个UserServiceProxy类去继承UserService,重写test方法,最先执行切点方法逻辑,然后执行目标对象的逻辑。定义的UserServiceProxy类就相当于代理类,它也属于UserService对象类型,因为是userService的子类。

还记得userService中有一个属性是orderService,那么这个代理对象中的orderService还有没有值呢,答案是没有。那orderService在哪儿呢,它其实在代理对象的target里面。因为target是初始化之前生成的userService对象。为什么代理类里面orderService是null呢,其实它没必要是设置orderService,因为代理对象里面有target,代理对象只需要把切点的方法执行完就行,剩下的交给target对象去执行就可以了。如果要设置orderService的话也可以。方法还是一样的。如下图
在这里插入图片描述

class(UserService) > 推断构造方法 > 实例化 > 对象(target) > 属性填充 > afterPropertiesSet (初始化) > AOP > 代理对象 > bean

根据上面这个流程spring创建一个声明周期。首先一个class类实例化前会通过构造方法去创建对象,如果有多个构造方法,它会推断该使用哪个来实例化。实例化完一个对象后,就该进行属性填充了,上面提到的给userService对象填充orderService属性。填充属性用到了Autowried和Resource注解。填充完后进行初始化。然后再判断要不要进行AOP,如果进行AOP会生成一个代理对象,最后得到一个代理对象的bean。如果不进行AOP,最后的bean就是前面实例化的对象

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值