分析Spring中Bean的生命周期

本文详细剖析了Spring中Bean的生命周期,从实例化、依赖注入到Aware接口、BeanPostProcessor处理,再到InitializingBean和init-method,最后是DisposableBean和destroy-method。文中通过实例代码展示了Bean从创建到销毁的全过程。

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

写在最前

从十一到现在两周,IOC部分源码读了一半多,是力气活,也是个精细活。全部写出来心有余力不足,所以找些重点写写。

简述 bean 实例化之前

Spring中不是启动容器时就开启bean的实例化进程,它首先会对资源进行读取并对bean进行初始化。

Spring将资源的定义和资源的加载区分开,Resource定义了统一的资源,默认实现是AbstractResource,资源的加载由ResourceLoader接口的不同实现类返回Resource。紧接着,解析Resource资源,将用户定义的Bean装载成BeanDefinition,每一个Bean对象都对应着一个BeanDefinitionBeanDefinition存在于IOC内部容器中的HashMap结构。再紧跟着,向IOC容器注册解析好的BeanDefinition,这个过程是通过BeanDefinitionRegistry接口来实现的。

初始化之后,会进行真正bean的加载,因为BeanDefinition不是想要的bean。初始化默认为懒加载,第一次调用getBean()时进行初始化。

首先得到可使用正确的beanName,这是涉及到别名或者factoryBean 。bean的作用域有singleton,prototype 和其他,Spring先尝试从缓存中加载单例bean,否则开始创建bean的实例。创建bean的实例可以理解为将BeanDefinition转换为BeanWrapper,BeanWarpper提供了get、set方法。之后还有一系列处理:MergedBeanDefinitionPostProcessor 属性合并,单例模式的循环依赖处理,属性填充,初始化bean。

在初始化bean这个过程中的代码,就包含了对XXXAware接口的处理,后置处理器,以及自定义的init-method方法。

Bean生命周期

回到最开始,看一下spring bean 的生命周期:

img

  1. 实例化Bean

    对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。

    对于ApplicationContext容器,当容器启动结束后,便实例化所有的bean。

    容器通过获取BeanDefination对象中的信息进行实例化。并且这一步仅仅是简单的实例化,并未进行依赖注入。

    实例化对象被包装在BeanWrapper对象中,BeanWrapper提供了设置对象属性的接口,从而避免了使用反射机制设置属性。

    在实例化bean的过程中,Spring采用策略模式决定采用反射还是 CGLIB 动态字节码。Spring 默认采用 CglibSubclassingInstantiationStrategy实例化bean,他既可以以反射实例化对象,还可以通过 CGLIB 的动态字节码的方式,以方法(setXxx)的方式注入对象实例化。

  2. 设置对象属性(依赖注入)

    实例化后的对象被封装在BeanWrapper对象中,并且此时对象仍然是一个原生的状态,并没有进行依赖注入。

    紧接着,Spring根据BeanDefinition中的信息进行依赖注入。

    并且通过BeanWrapper提供的设置属性的接口完成依赖注入。

  3. 注入Aware接口

    紧接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给bean。

    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);
            }
        }
    }
    
  4. BeanPostProcessor

    当经过上述几个步骤后,bean对象已经被正确构造,但如果你想要对象被使用前再进行一次自定义的处理,就可以通过BeanPostProcessor接口实现。

    该接口提供了两个函数:

    • postProcessBeforInitialzation(Object bean, String beanName)

      当前正在初始化的bean对象会被传递进来,我们就可以对这个bean做任何处理。

      这个函数会先于InitialzationBean执行,因此称为前置处理。

      所有Aware接口的注入就是在这一步完成的。

    • postProcessAfterInitialzation(Object bean, String beanName)

      当前正在初始化的bean对象会被传递进来,我们就可以对这个bean做任何处理。

      这个函数会在initialzationBean完成后执行,因此成为后置处理

      public interface BeanPostProcessor {
          @Nullable
          default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              return bean;
          }
      
          @Nullable
          default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              return bean;
          }
      }
      
  5. InitializingBean 与 init-method

    当BeanPostProcessor的前置处理完成后就会进入本阶段。

    InitialzingBean接口只有一个函数:

    • afterPropertiesSet()

    这一阶段也可以在bean正式构造完成前增加我们自定义的逻辑,但它与前置处理不同,由于该函数并不会把当前bean传递进来,因此这一步没办法处理对象本身,只能增加一些额外的逻辑。若要使用它,我们需要让bean实现该接口,并把要增加的逻辑写在该函数中。然后Spring会在前置处理完成后检测当前bean是否实现了该接口,并执行afterPropertiesSet函数。

    当然,Spring为了降低对客户代码的侵入性,给bean的配置提供了init-method属性,该属性指定了在这一阶段需要执行的函数名。Spring便会在初始化阶段执行我们设置的函数。init-method本质上仍然使用了InitializingBean的接口。

    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.isDebugEnabled()) {
                logger.debug("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) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }
    
  6. DisposableBean 和 destroy-method

    和init-method一样,通过给destroy-method指定函数,就可以在bean销毁前执行指定的逻辑。

实例代码

先来一段代码,看看Spring中Bean的生命周期

public class LifeCycleBean implements BeanNameAware, BeanFactoryAware, BeanClassLoaderAware, InitializingBean,DisposableBean  {
    private String test;

    public LifeCycleBean() {
        System.out.println("构造函数调用...");
    }

    public String getTest() {
        return test;
    }

    public void display(){
        System.out.println("方法调用...");
    }

    public void setTest(String test) {
        System.out.println("属性注入....");
        this.test = test;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("BeanNameAware 被调用...");
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("BeanClassLoaderAware 被调用...");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware 被调用...");
    }

    public void initMethod(){
        System.out.println("init-method 被调用...");
    }

    public void destroyMethod(){
        System.out.println("destroy-method 被调用...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean afterPropertiesSet 被调动...");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy 被调动...");
    }
}
<bean id="lifeCycleBean" class="com.example.bean.LifeCycleBean"
      init-method="initMethod" destroy-method="destroyMethod">
    <property name="test" value="test"/>
</bean>
public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");

    LifeCycleBean lifeCycleBean = (LifeCycleBean) context.getBean("lifeCycleBean");
    lifeCycleBean.display();

    context.destroy();
}

运行结果如下:

构造函数调用...
属性注入....
BeanNameAware 被调用...
BeanClassLoaderAware 被调用...
BeanFactoryAware 被调用...
InitializingBean afterPropertiesSet 被调动...
init-method 被调用...
方法调用...
DisposableBean destroy 被调动...
destroy-method 被调用...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值