spring初始化bean时执行某些方法完成特定的初始化操作

在项目中经常会在容器启动时,完成特定的初始化操作,如资源文件的加载等。

一 实现的方式有三种:

1.使用@PostConstruct注解,该注解作用于void方法上

2.在配置文件中配置init-method方法

<bean id="student" class="com.demo.spring.entity.Student" init-method="init2">
        <property name="name" value="景甜"></property>
        <property name="age" value="28"></property>
        <property name="school" ref="school"></property>
</bean>

3.将类实现InitializingBean接口

package com.demo.spring.entity;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

/**
 * @author chenyk
 * @date 2018年5月8日
 */
@Component("student")
public class Student implements InitializingBean{
    private String name;
    private int age;
    
    private School school;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public School getSchool() {
        return school;
    }
    public void setSchool(School school) {
        this.school = school;
    }
    
    //1.使用postconstrtct注解
    @PostConstruct
    public void init(){
        System.out.println("执行 init方法");
    }
     
    //2.在xml配置文件中配置init-method方法
    public void init2(){
        System.out.println("执行init2方法 ");
    }
    
    //3.实现InitializingBean接口
    public void afterPropertiesSet() throws Exception {
        System.out.println("执行init3方法");
    }
    
}

执行结果:

执行 init方法
2018-06-11 10:09:16,195 DEBUG [AbstractAutowireCapableBeanFactory.java:1671] : Invoking afterPropertiesSet() on bean with name 'student'
执行init3方法
2018-06-11 10:09:36,459 DEBUG [AbstractAutowireCapableBeanFactory.java:1731] : Invoking init method 'init2' on bean with name 'student'
执行init2 方法

二 实现原理:

由以上执行结果可知:先执行@PostConstruct注解的方法,然后是实现了InitializingBean接口的afterPropertiesSet方法,最后执行在配置文件中配置的init-method方法。至于为什么是这个顺序,可以看源码:

在 AbstractAutowireCapableBeanFactory 类中

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

然后进入到 invokeInitMethods 方法中

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

        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean &amp;&amp; (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        @Override
                        public Object run() throws Exception {
                            ((InitializingBean) bean).afterPropertiesSet();
                            return null;
                        }
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
          //直接调用 InitializingBean 接口中的 afterPropertiesSet 方法
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

        if (mbd != null) {
            String initMethodName = mbd.getInitMethodName();
            if (initMethodName != null &amp;&amp; !(isInitializingBean &amp;&amp; "afterPropertiesSet".equals(initMethodName)) &amp;&amp;
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
          //进入该方法可知通过反射的方式调用init-method方法
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

所以,初始化方法的执行顺序 afterPropertiesSet() > init-method()

博客园的第一篇文章。感觉博客园很干净,文章排版特别是插入代码格式看起来很舒服。就不吐槽csdn了。