Spring Bean加载过程(二)

本文详细剖析了Spring框架中Bean的初始化过程,包括BeanFactoryPostProcessor与BeanPostProcessor的使用时机,以及Bean实例化、依赖注入和初始化的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  
  在前面 Spring Bean加载过程(一) 文章中,分析了在refresh()方法中obtainFreshBeanFactory()执行完后所有的BeanDefinition已经初始化好了。之后会调用下面的代码:

    //为容器的某些子类指定特殊的BeanPost事件处理器
    postProcessBeanFactory(beanFactory);  
                
    //调用所有注册的BeanFactoryPostProcessor的Bean  
    invokeBeanFactoryPostProcessors(beanFactory);  
                
    //为BeanFactory注册BeanPost事件处理器.  
    //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件  
    registerBeanPostProcessors(beanFactory);  
                
    //初始化信息源,和国际化相关.  
    initMessageSource();  
                
    //初始化容器事件传播器.  
    initApplicationEventMulticaster();  
                
    //调用子类的某些特殊Bean初始化方法  
    onRefresh();  
                
    //为事件传播器注册事件监听器.  
    registerListeners();  
                
    //初始化所有剩余的单态Bean.  
    finishBeanFactoryInitialization(beanFactory);  
                
    //初始化容器的生命周期事件处理器,并发布容器的生命周期事件  
    finishRefresh();  

  这里会涉及到BeanFactoryPostProcessor、BeanPostProcessor的调用,先不细入分析代码,只是大概介绍一下调用的先后顺序:

  
  在上面的过程中,会调用beanFactory#getBean()来取得bean,来看下getBean()方法,我们知道BeanFactory接口中定义了几个getBean方法,就是向IoC容器索取管理的Bean的方法,在getBean时会完成对应bean的初始化。由于调用的层次比较复杂,最终调用了AbstractBeanFactory#getBean()方法,该方法实际上是调用了其AbstractBeanFactory#doGetBean()方法。
  在doGetBean()方法中,如果Bean定义的单态模式(Singleton),则容器在创建之前先从缓存中查找,以确保整个容器中只存在一个实例对象。如果Bean定义的是原型模式(Prototype),则容器每次都会创建一个新的实例对象。除此之外,Bean定义还可以扩展为指定其生命周期范围。具体的Bean实例对象的创建过程由createBean()方法完成,其具体的实现类是AbstractAutowireCapableBeanFactory,最终的bean的创建是AbstractAutowireCapableBeanFactory#doCreateBean

	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		//......

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			if (exposedObject != null) {
				exposedObject = initializeBean(beanName, exposedObject, mbd);
			}
		}
		//......

		return exposedObject;
	}

  createBeanInstance()方法是根据XML的定义调用bean的有参或无参构造函数。跟踪该方法,我们最终会发现有个getInstantiationStrategy()方法,该方法的作用是获得实例化的策略对象,也就是指通过哪种方案进行实例化的过程,Spring当中提供了两种实例化方案:BeanUtils和CGLIB方式。BeanUtils实现机制是通过Java的反射机制,Cglib是一个第三方类库采用的是一种字节码加强方式机制。
  populateBean()方法会获得BeanDefinition中设置的property信息,对这些property进行赋值,即依赖注入的过程。在这个方法里完成对属性的注入,比如setXxx()方法的调用、属性的注解注入。

  对于initializeBean()方法:

	protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					invokeAwareMethods(beanName, bean);
					return null;
				}
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}

		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}

  invokeAwareMethods()方法判断是BeanNameAware、BeanFactoryAware之类的Aware类型,如果是的话就执行对应方法。
  applyBeanPostProcessorsBeforeInitialization()方法是如果实现了BeanPostProcessor接口,这里会执行postProcessBeforeInitialization方法。
  invokeInitMethods()方法中,先判断是否实现了InitializingBean接口,如果是执行afterPropertiesSet()方法,然后如果配置了init-method就执行initMethod方法。
  applyBeanPostProcessorsAfterInitialization()方法是如果实现了BeanPostProcessor接口,这里会执行postProcessAfterInitialization方法。
  到此为止一个BeanFactoryPostProcessor的Bean就初始化完成了。

  于是就可以通过BeanFactoryPostProcessor的postProcessBeanFactory()的调用,来修改某些beanDefinition的值,示例:

   @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanNames = beanFactory.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            BeanDefinition bd = beanFactory.getBeanDefinition(beanName);

            System.out.println(bd.getBeanClassName());
            PropertyValue[] pvArray = bd.getPropertyValues().getPropertyValues();
            for (PropertyValue pv : pvArray) {
                System.out.println(pv.getName() + "---" + pv.getValue());
            }

            ConstructorArgumentValues cas = bd.getConstructorArgumentValues();
            for (ConstructorArgumentValues.ValueHolder valueHolder : cas.getIndexedArgumentValues().values()) {
                System.out.println(valueHolder.getName() + "---" + valueHolder.getValue());
            }

            for (ConstructorArgumentValues.ValueHolder valueHolder : cas.getGenericArgumentValues()) {
                System.out.println(valueHolder.getName() + "---" + valueHolder.getValue());
            }
        }
    }

  Spring中的PropertyPlaceholderConfigurer正是通过这种方式来实现了配置宏替换。

  • 需要注意的是,BeanPostProcessor在源码注释已经表述了,只有当其它非实现BeanPostProcessor的bean且在同一个容器的bean在初始化的时候,才会回调BeanPostProcessor重写的那些方法,所以一个继承了BeanPostProcessor的类初始化会发现是不会有override方法的回调的。

  执行顺序:Constructor > @PostConstruct > InitializingBean > init-method,@PostConstruct优先于后者是因为CommonAnnotationBeanPostProcessor这个类,它继承自InitDestroyAnnotationBeanPostProcessor,用于处理@PostConstruct这类注解的BeanPostProcessor,所以先于InitializingBean执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值