SpringBean的生命周期

SpringBena的生命周期

  1. Spring对bean进行实例化,调用Bean的构造参数

  2. 调用bean的set方法将属性注入到bean的属性

  3. 检查bean是否实现beanNameaware,beanFactoryAware
    当经过上述几个步骤后,bean对象已经被正确构造,但如果你想要对象被使用前再进行一些自定义的处理,就可以通过BeanPostProcessor接口实现。

    该接口提供了两个函数:postProcessBeforeInitialzation( Object bean, String beanName ) 当前正在初始化的bean对象会被传递进来,我们就可以对这个bean作任何处理。
    这个函数会先于InitialzationBean执行,因此称为前置处理。 所有Aware接口的注入就是在这一步完成的。postProcessAfterInitialzation( Object bean, String beanName )
    当前正在初始化的bean对象会被传递进来,我们就可以对这个bean作任何处理。 这个函数会在InitialzationBean完成后执行,因此称为后置处理。

  4. 查询是否实现benaPostProcessor,Spring会在初始化方法的前后分别调用postProcessBeforeInitialization和postProcessAfterInitialization方法

  5. 查看bean是否实现InitalizingBean接口,将调用afterPropertiesSet()方法
    当BeanPostProcessor的前置处理完成后就会进入本阶段。
    InitializingBean接口只有一个函数:afterPropertiesSet()这一阶段也可以在bean正式构造完成前增加我们自定义的逻辑,但它与前置处理不同,由于该函数并不会把当前bean对象传进来,因此在这一步没办法处理对象本身,只能增加一些额外的逻辑。 若要使用它,我们需要让bean实现该接口,并把要增加的逻辑写在该函数中。
    然后Spring会在前置处理完成后检测当前bean是否实现了该接口,并执行afterPropertiesSet函数。当然,Spring为了降低对客户代码的侵入性,给bean的配置提供了init-method属性,该属性指定了在这一阶段需要执行的函数名。
    Spring便会在初始化阶段执行我们设置的函数。init-method本质上仍然使用了InitializingBean接口。

  6. 查看是否声明初始化方法

  7. 使用bean,bean将会一直保留在应用的上下文中,直到被销毁

  8. 检查bena是否实现DisposableBean接口,Spring会调用他们的destory方法

  9. 如果bean声明销毁方法,该方法也会被调用

怎么用BeanPostProcessor,直译过来,就是“对象后处理器”,那么这个“后”,是指什么之后呢?BeanPostProcessor(下面简称BBP)。

试试便知。

@Component
public class Bean4BBP {

 private static final Logger log = LoggerFactory.getLogger(Bean4BBP.class);

 public Bean4BBP(){
 log.info("construct Bean4BBP");
 }
}

然后再写一个BeanPostProcessor,这时发现它是一个接口,没关系,那就写一个类实现它,CustomBeanPostProcessor:

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {

 private static final Logger log = LoggerFactory.getLogger(CustomBeanPostProcessor.class);

 public CustomBeanPostProcessor() {
 log.info("construct CustomBeanPostProcessor");
 }

 @Override
 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 if (bean instanceof Bean4BBP) {
 log.info("process bean before initialization");
 }
 return bean;
 }

 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 if (bean instanceof Bean4BBP) {
 log.info("process bean after initialization");
 }
 return bean;
 }
}

然后启动我们的Spring Boot项目(直接运行Application类),看这几条日志打印的顺序:

construct CustomBeanPostProcessor
construct Bean4BBP
process bean before initialization
process bean after initialization

结论:“对象后处理器”,指的是“对象创建后处理器”。
BBP在Spring对象初始化流程的位置:
在这里插入图片描述
BBP的典型使用 - AOP

使用Spring AOP时,有没有发现,带有切面逻辑的对象,注入进来之后,都不是原来的对象了,aspectService是一个…$$EnhanceBySpringCGlib的对象,这其实和Spring AOP用到的动态代理有关。

这也就意味着,**最终放进Spring容器的,必须是代理对象,**而不是原先的对象,这样别的对象在注入时,才能获得带有切面逻辑的代理对象。

那么Spring是怎么做到这一点的呢?正是利用了这篇文章讲到的BBP。

显然,我只需要写一个BBP,在postProcessBeforeInitialization或者postProcessAfterInitialization方法中,对对象进行判断,看他需不需要织入切面逻辑,如果需要,那我就根据这个对象,生成一个代理对象,然后返回这个代理对象,那么最终注入容器的,自然就是代理对象了。

这个服务于Spring AOP的BBP,叫做AnnotationAwareAspectJAutoProxyCreator.

讲到Aop,ioc

IOC
所谓的控制反转。通俗地讲,就是把原本需要程序员自己创建和维护的一大堆bean统统交由Spring管理。
也就是说,spring将我们从盘根错节的依赖关系中解放路,当前对象如果需要依赖另一个对象,只要打上一个@autowired注解,spring帮你安装

AOP
面向切面编程,比如日志,事务,一个交叉业务就是要切入系统的一个方面,交叉业务的编程问题即为面向切面编程。aop的目标就是使交叉业务模块化,做法就是将切面转移到方式方法的周围。
原先不用aop的时候,交叉业务的代码直接硬编码在方法内部的前后而AOP则是把交叉业务写在方法调用前后
。呢么为什么AOP不把代码也写在方法内部前后呢?两点原因

一、首先,这与AOP的底层实现方式有关:动态代理其实就是代理对象调用目标对象的同名方法,并在调用前后增强代码。
在这里插入图片描述
二、其次,这两种最终运行效果是一样的,所以没什么好纠结的。

模块化,就是将切面做成一个可以管理的状态,比如打印日志,不再是直接硬编码在方法中的零散语句,而是做成一个切面,通过通知的方式去执行切面代码。

后置处理器分为很多种,属于Spring的扩展点
在这里插入图片描述
Spring事务基于Spring AOP,Spring AOP底层用的动态代理,动态代理有两种方式:
基于接口代理(JDK代理)
基于接口代理,凡是类的方法非public修饰,或者用了static关键字修饰,那这些方法都不能被Spring AOP增强
基于CGLib代理(子类代理)
基于子类代理,凡是类的方法使用了private、static、final修饰,那这些方法都不能被Spring AOP增强

接口不可以实现方法,只可以定义方法,所以不能使用静态方法(因为静态方法必须实现)。

如果使用private,static无法覆盖子类所以不可以使用aop代理
借鉴知乎多篇高赞文章

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值