Spring中Bean的生命周期

本文详细解析了Spring框架中Bean的生命周期,包括单例和原型的区别,以及实例化、属性赋值、初始化(Aware接口、BeanPostProcessor、InitializingBean和自定义初始化方法)、销毁等各阶段的过程和Spring提供的扩展点如Aware接口和BeanPostProcessor的使用。
摘要由CSDN通过智能技术生成

目录

什么是 Spring Bean 的生命周期?

spring中的扩展点

总结


什么是 Spring Bean 的生命周期?

对于普通的 Java 对象,当 new 的时候创建对象,然后该对象就能够使用了。一旦该对象不再被使用,则由 Java 自动进行垃圾回收。

而 Spring 中的对象是 bean,bean 和普通的 Java 对象没啥大的区别,只不过 Spring 不再自己去 new 对象了,而是由 IoC 容器去帮助我们实例化对象并且管理它,我们需要哪个对象,去问 IoC 容器要即可。IoC 其实就是解决对象之间的耦合问题,Spring Bean 的生命周期完全由容器控制。

我们说的 Spring Bean 的生命周期主要指的是 singleton bean,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。

那么Spring 中的 bean 的作用域有哪些?

singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
prototype : 每次请求都会创建一个新的 bean 实例。
request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
global-session: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

Bean 的生命周期概括起来就是 4 个阶段

  1. 实例化(Instantiation)
  2. 属性赋值(Populate)
  3. 初始化(Initialization)
  4. 销毁(Destruction)

实例化:第 1 步,实例化一个 bean 对象;

属性赋值:第 2 步,为 bean 设置相关属性和依赖;

初始化:第 3~7 步,步骤较多,其中第 5、6 步为初始化操作,第 3、4 步为在初始化前执行,第 7 步在初始化后执行,该阶段结束,bean对象才能被用户使用;

销毁:第 8~10步,第8步不是真正意义上的销毁(还没使用呢),而是先在使用前注册了销毁的相关调用接口,为了后面第9、10步真正销毁 bean 时再执行相应的方法。

shift+shift 搜索 AbstractAutowireCapableBeanFactory ,查看创建bean的方法 doCreateBean

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
    }

    if (instanceWrapper == null) {
    	// 实例化阶段
        instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    }

    ...

    Object exposedObject = bean;

    try {
    	// 属性赋值阶段
        this.populateBean(beanName, mbd, instanceWrapper);
        // 初始化阶段
        exposedObject = this.initializeBean(beanName, exposedObject, mbd);
    } catch (Throwable var18) {
        ...
    }

    ...
    try {
          //销毁化阶段
          this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
          return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,             "Invalid destruction signature", var16);
        }
}

这里追踪初始化阶段方法的实现,先点进initializeBean()方法。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        //3.检查aware接口,并配置相关依赖
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(() -> {
                this.invokeAwareMethods(beanName, bean);
                return null;
            }, this.getAccessControlContext());
        } else {
            this.invokeAwareMethods(beanName, bean);
        }


        //4.BeanPostProcessor 前置处理器
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        //5.若实现 InitializingBean 接口,调用 afterPropertiesSet()方法
        //6.若配置自定义的Init方法,则执行

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

        //7.BeanPostProcessor 后置处理器

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

        return wrappedBean;
    }

点进invokeAwareMethods()方法查看第三步是怎么实现的

private void invokeAwareMethods(String beanName, Object bean) {
        //如果bean实现了Aware接口
        if (bean instanceof Aware) {
            //接口1
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware)bean).setBeanName(beanName);
            }
            
            //接口2
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = this.getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
                }
            }

            //接口3
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware)bean).setBeanFactory(this);
            }
        }

    }

点进invokeInitMethods()方法查看源码,查看5、6步骤的实现

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
        //5.若实现 InitializingBean 接口,调用 afterPropertiesSet()方法
        boolean isInitializingBean = bean instanceof InitializingBean;
        if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }

            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged(() -> {
                        ((InitializingBean)bean).afterPropertiesSet();
                        return null;
                    }, this.getAccessControlContext());
                } catch (PrivilegedActionException var6) {
                    throw var6.getException();
                }
            } else {
                ((InitializingBean)bean).afterPropertiesSet();
            }
        }

        //6.若配置自定义的Init方法,则执行
        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
                this.invokeCustomInitMethod(beanName, bean, mbd);
            }
        }

    }

其他流程的具体实现大家可以自己去追踪源码,这里就不详细追踪了。

总之我们从 Spring 的源码中可以直观的看到其执行过程,而我们记忆其过程便可以从这 4 个阶段出发,实例化属性赋值初始化销毁。其中细节较多的便是初始化,涉及了 Aware、BeanPostProcessor、InitializingBean、init-method 的概念。这些都是 Spring 提供的扩展点

Spring中的扩展点

1.Aware 接口

若 Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖。所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源。
Spring 中提供的 Aware 接口有:

1.BeanNameAware:注入当前 bean 对应 beanName;

2.BeanClassLoaderAware:注入加载当前 bean 的 ClassLoader;

3.BeanFactoryAware:注入当前BeanFactory容器 的引用。

代码实现:

AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(String beanName, Object bean) {
        //如果bean实现了Aware接口
        if (bean instanceof Aware) {
            //接口1
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware)bean).setBeanName(beanName);
            }
            
            //接口2
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = this.getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
                }
            }

            //接口3
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware)bean).setBeanFactory(this);
            }
        }

    }

BeanPostProcessor
BeanPostProcessor 是 Spring 为修改 bean提供的强大扩展点,其可作用于容器中所有 bean,其定义如下:

public interface BeanPostProcessor {

    // 初始化前置处理
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
        return bean; 
    } 
    // 初始化后置处理 
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
        return bean; 
    } 
} 


常用场景有:

1.对于标记接口的实现类,进行自定义处理

2.为当前对象提供代理实现。例如 Spring AOP 功能,生成对象的代理类,然后返回。

代码:AbstractAutoProxyCreator.java

//前置处理器
 public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        Object cacheKey = this.getCacheKey(beanClass, beanName);
        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }

            if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
        if (targetSource != null) {
            if (StringUtils.hasLength(beanName)) {
                this.targetSourcedBeans.add(beanName);
            }

            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        } else {
            return null;
        }
    }

InitializingBean 和 init-method

InitializingBean 和 init-method 是 Spring 为 bean 初始化提供的扩展点。

InitializingBean接口 的定义如下:

public interface InitializingBean { 
    void afterPropertiesSet() throws Exception; 
} 

当 Spring 容器创建 Bean 实例后,会检测是否实现了 InitializingBean 接口,如果实现了,则会自动调用 afterPropertiesSet() 方法,执行初始化逻辑。

通过 @Bean 注解的 initMethod 属性来定义 Bean 的初始化方法。具体来说,你可以在 @Bean 注解中使用 initMethod 属性指定一个方法作为 Bean 的初始化方法。该方法会在 Bean 实例化后自动调用,执行初始化逻辑。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean(initMethod = "init")
    public MyBean myBean() {
        return new MyBean();
    }
}
public class MyBean {

    public void init() {
        // 在这里实现 Bean 的初始化逻辑
        System.out.println("MyBean 初始化完成");
    }
}

总结

实例化

1.Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化

设置属性

2.Bean实例化后对将Bean的引入和值注入到Bean的属性中

初始化

3.如果Bean实现了BeanNameAware接口,注入当前 bean 对应 beanName;如果Bean实现了BeanClassLoaderAware接口,注入加载当前 bean 的 ClassLoader;如果Bean实现了BeanFactoryAware接口,注入当前BeanFactory容器 的引用。

4.如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。

5.如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。

6.如果bean使用init-method声明了初始化方法,该方法也会被调用

7.如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。

为销毁做准备

8.注册Destruction相关的回调接口,为后续的销毁做准备

使用

此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。

销毁

9.如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法

10.如果bean使用了destory-method 声明销毁方法,该方法也会被调用。

  • 51
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值