Spring Bean加载过程(二)

来源:互联网 发布:linux误删除文件恢复 编辑:程序博客网 时间:2024/06/17 15:07

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

invokeBeanFactoryPostProcessors(beanFactory);

在方法里会从beanFactory中获取实现了BeanFactoryPostProcessor的BeanDefinition,并从beanFactory中getBean()来取得该bean,并调用其实现的postProcessBeanFactory()方法。

先来看下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方法的回调的。

补充:
实例化Bean的过程中有以下几个节点:
1)构造函数调用、设置属性值;
2)调用Bean中的BeanNameAware.setBeanName()方法,如果该Bean实现了BeanNameAware接口;
3)调用Bean中的BeanFactoryAware.setBeanFactory()方法,如果该Bean实现了BeanFactoryAware接口;
4)调用BeanPostProcessors.postProcessBeforeInitialization()方法;
5)调用Bean中的afterPropertiesSet方法,如果该Bean实现了InitializingBean接口;
6)调用Bean中的init-method,通常是在配置bean的时候指定了init-method,例如:<bean class="beanClass"init-method="init"></bean>
7)调用BeanPostProcessors.postProcessAfterInitialization()方法;
8)如果该Bean是单例的,则当容器销毁并且该Bean实现了DisposableBean接口的时候,调用destory方法;如果该Bean是prototype,则将准备好的Bean提交给调用者,后续不再管理该Bean的生命周期。


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