SpringBean的生命周期

SpringBean的生命周期:

简单来说spring的生命周期分为四个阶段,

  • 第一阶段:实例化阶段 Instantiation
  • 第二阶段:属性赋值 Populate
  • 第三阶段:初始化阶段 Initialization
  • 第四阶段:销毁阶段 Destruction

整体流程图如下:

在这里插入图片描述


1.实例化Bean对象:

在这一步主要做的就是类的定义,也就是做我们BeanDefinition的内容。
在这里插入图片描述
ComponentScan:主要是定义spring要扫描哪些包下的文件,需要把哪些文件加入spring容器中。

在确定我们扫描哪些包下的文件后,会先过滤不是.class的文件。然后在判断对应的.class类的文件是否存在Component注解。
这个时候也会获取我们Component注解的内容,如果你对类进行命名,就拿你注解对应的value。如果Component注解没有命名就会调用Introspector.decapitalize()方法; 进行命名。

在spring中有一个 beanPostProcessorsList,它主要就是存储我们哪些类定义了BeanPostProcessor的接口,这就可以为后面我们使用前置、后置处理器做准备。(这里会根据类加载器反射创建实现接口的对象,加入list中)

	/** BeanPostProcessors to apply. */
	private final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList();

做完以上步骤后,就开始进行我们BeanDefinition的内容。在这个时候我们还没有完成对象的创建,我们的bean还只是一个Class。因为Class无法完成bean的抽象,比如bean的作用域,bean的注入模型,bean是否是懒加载等等信息,Class是无法抽象出来的,故而需要一个BeanDefinition类来抽象这些信息,以便于spring能够完美的实例化一个bean。

简单理解就是,spring 在扫描时,如果一个类加入了Scan注解定义这个bean是单例的。在BeanDefinition中有两个属性,一个是Class,一个是scope。Class存储的是当前扫描类的Class地址,而scope是标注该Class是单例还是多例。在后续创建bean时就可以识别。

而在spring中它有一个BeanDefinitionMap。它主要就是存储我们这些BeanDefinition,它的key就是我们beanName,value就是BeanDefinition。

  private ConcurrentHashMap <String,BeanDefinition>BeanDefinitionMap=new ConcurrentHashMap<>();

在creatBean方法中,根据我们定义的BeanDefinition通过反射进行对象的创建。这个时候会通过调用我们的无参构造方法进行创建。

如果你实现了有参构造方法,就会调用你的有参构造方法进行对象的创建,并会给你的参数进行赋值。,如果B对象在spring容器中有多个对象,比如B b, B b1, B b2。这个时候spring会先byType,在byName。先找到有哪些是B对象,如果只有一个B对象就直接注入,有多个就根据定义的名称进行注入。

// 
public class A {
	private B b;
// 单个构造方法可以进行属性注入
	public void A(B b){
	this.b=b;
	}
// 如果是多个构造方法,没有无参构造方法spring就会报错
    public void A(B b,String a){
	this.b=b;
	}
}

当然在这里就可以看出,会出现循环依赖的问题。假如A的构造方法参数是B,而B的构造方法参数是C,C的构造方法参数是A。那么这三个对象就会出现循环依赖问题。


2.设置对象属性:

这一步主要就是通过扫描我们该类下所有的成员属性,判断是否有@Autowired注解,如果有就从Spring容器中进行注入。

如果对象在spring容器 中就直接注入,不在容器中就会调用creatBean方法再次创建对象。

当然在这一步也会出现循环依赖问题,比如A注入了自己,然后进行对象属性创建,又注入了自己。就会一直循环注入自己。


3.处理Aware接口:

Sring 容器在初始化主动检测当前 bean 是否实现了 Aware 接口,如果实现了则回调其 set 方法将相应的参数设置给该 bean ,这个时候该 bean 就从 Spring 容器中取得相应的资源。

  • [ ]①如果这个Bean实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,传入Bean的名字;
  • [ ]②如果这个Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。
  • [ ]②如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。

这里主要就是spring会调用你的接口,也就是接口回调,给你传递一些信息。


4.BeanPostProcessor前置处理

BeanPostProcessor 可以理解为是 Spring 的一个工厂钩子(其实 Spring 提供一系列的钩子,如 Aware 、InitializingBean、DisposableBean),它是 Spring 提供的对象实例化阶段强有力的扩展点,允许 Spring 在实例化 bean 阶段对其进行定制化修改,比较常见的使用场景是处理标记接口实现类或者为当前对象提供代理实现(例如 AOP)。
在这里插入图片描述
在spring源码中会先通过getBeanPostProcessors()拿到上面初始化前定义的beanPostProcessors数组,在通过循环的方式去判断当bean有没有实现BeanPostProcessor接口。


	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

5. InitializingBean和init-method

这里和Aware接口不同的是,前面是spring回调你的接口,这里是spring会调用你的方法。

// AbstractAutowireCapableBeanFactory.java

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
        throws Throwable {
    // 首先会检查是否是 InitializingBean ,如果是的话需要调用 afterPropertiesSet()
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) { // 安全模式
            try {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                    // 属性初始化的处理
                    ((InitializingBean) bean).afterPropertiesSet();
                    return null;
                }, getAccessControlContext());
            } catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        } else {
            // 属性初始化的处理
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }

    if (mbd != null && bean.getClass() != NullBean.class) {
        // 判断是否指定了 init-method(),
        // 如果指定了 init-method(),则再调用制定的init-method
        String initMethodName = mbd.getInitMethodName();
        if (StringUtils.hasLength(initMethodName) &&
                !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            // 激活用户自定义的初始化方法
            // 利用反射机制执行
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

首先,检测当前 bean 是否实现了 InitializingBean 接口,如果实现了则调用其 afterPropertiesSet() 方法。
然后,再检查是否也指定了 init-method,如果指定了则通过反射机制调用指定的 init-method 方法。

6.BeanPostProcessor后置处理

这里也是和前置处理器一样,如果实现了接口会调用你后置处理器的方法。

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

7. 对象初始化完成,可以进行使用


8.DisposableBean

在容器进行关闭之前,如果该 bean 实现了 DisposableBean 接口,则调用 destroy() 方法

在容器进行关闭之前,如果该 bean 配置了 destroy-method ,则调用其指定的方法。

它与InitializingBean 和 init-method 用于对象的自定义初始化工作相似,DisposableBean和 destroy-method 则用于对象的自定义销毁工作。

当一个 bean 对象经历了实例化、设置属性、初始化阶段,那么该 bean 对象就可以供容器使用了(调用的过程)。当完成调用后,如果是 singleton 类型的 bean ,则会看当前 bean 是否应实现了 DisposableBean 接口或者配置了 destroy-method 属性,如果是的话,则会为该实例注册一个用于对象销毁的回调方法,便于在这些 singleton 类型的 bean 对象销毁之前执行销毁逻辑。


至此spring中Bean的一生就结束了,关于spring是怎么解决循环依赖的。我将会在下一章给大家解答。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值