Spring源碼解析(十一)-初始化bean

Spring版本

5.2.5.RELEASE

參考

《芋道源碼》

源碼解讀

1. AbstractAutowireCapableBeanFactory#initializeBean

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            // 通過aware接口進行一些set設置
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 初始化之前應用PostProcessors
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // 應用init方法
            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()) {
            // 初始化之后應用beanProcessors
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

主流程主要包含四個步驟:

  • invokeAwareMethods進行一些屬性的設置
  • applyBeanPostProcessorsBeforeInitialization應用BeanPostProcessorsapplyBeanPostProcessorsBeforeInitialization方法
  • invokeInitMethods應用初始化方法
  • applyBeanPostProcessorsAfterInitialization應用BeanPostProcessorsapplyBeanPostProcessorsAfterInitialization

2. AbstractAutowireCapableBeanFactory#invokeAwareMethods

    private void invokeAwareMethods(final String beanName, final Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }

Aware接口是spring提供的一種回調(diào)機制,這里簡單地設置了beanNamebeanClassLoaderbeanFactory的屬性,關于Aware接口可戳// TODO

3. AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

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

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            // 應用每個PostProcessors
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

獲取到BeanPostProcessor集合,遍歷,應用每個BeanPostProcessorpostProcessBeforeInitialization方法,如果返回值為空,則返回上一次處理后的bean

4. AbstractAutowireCapableBeanFactory#invokeInitMethods

    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {

        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 {
                // afterPropertiesSet提供了一個機會在properties設置之后去改變properties
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                // 通過反射調(diào)用自定義初始化方法
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

做了倆件事:

  • 首先判斷bean是否是InitializingBean類型,如果是,應用afterPropertiesSet方法,從方法名可以看出,該方法提供了一個在設置完畢property之后再去修改property的機會
  • 應用自定義的init-method方法

4.1 InitializingBean

public interface InitializingBean {

    /**
     * Invoked by the containing {@code BeanFactory} after it has set all bean properties
     * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
     * <p>This method allows the bean instance to perform validation of its overall
     * configuration and final initialization when all bean properties have been set.
     * @throws Exception in the event of misconfiguration (such as failure to set an
     * essential property) or if initialization fails for any other reason
     */
    void afterPropertiesSet() throws Exception;

}

InitializingBean接口僅包含afterPropertiesSet一個方法,下面通過一個小demo來展示其效果

4.1.1 demo

4.1.1.1 Teacher.java
public class Teacher implements InitializingBean {

    private String name;


    @Override
    public void afterPropertiesSet() throws Exception {
        name = "name set by afterPropertiesSet";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
4.1.1.2 spring.xml
    <bean id="teacher" class="com.kungyu.custom.element.Teacher">
        <property name="name" value="name set by property label"/>
    </bean>
4.1.1.3 測試
public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        Teacher teacher = (Teacher) context.getBean("teacher");
        System.out.println(teacher.getName());

    }
}
4.1.1.4 結(jié)果
afterPropertiesSet

4.1.2 結(jié)論

可以看到,在spring.xml中,name屬性設置的name set by property label已經(jīng)被afterPropertiesSet方法中的name set by afterPropertiesSet所覆蓋

4.2 init-method

對4.1中的demo稍加修改

4.2.1 demo

4.2.1.1 Teacher.java
public class Teacher implements InitializingBean {

    private String name;


    @Override
    public void afterPropertiesSet() throws Exception {
        name = "name set by afterPropertiesSet";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void initMethod() {
        this.name = "name set by init method";
    }
}
4.2.1.2 spring.xml
    <bean id="teacher" class="com.kungyu.custom.element.Teacher" init-method="initMethod">
        <property name="name" value="name set by property label"/>
    </bean>
4.2.1.3 結(jié)果
init-method

4.2.2 源碼解析

        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                    // 如果init-method設置為afterPropertiesSet,那么前面已經(jīng)運行過了,沒必要再跑一遍
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                // 通過反射調(diào)用自定義初始化方法
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }

這里做了一個優(yōu)化,如果init-method設置為afterPropertiesSet方法,那么其實4.1中已經(jīng)應用了init-method,就無需再次運行了,而invokeCustomInitMethod方法的核心在于使用反射來應用init-method方法:

ReflectionUtils.makeAccessible(methodToInvoke);
methodToInvoke.invoke(bean);

5. AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization

    @Override
    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;
    }

邏輯與第三點大同小異

總結(jié)

初始化bean整體邏輯相對于其他流程來說,可以說是簡單了很多,通過倆個小demo,也更清晰地理解了源碼的執(zhí)行流程,沒有什么比實例來得更有說服力了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容