Bean 的生命周期之初始化

9 篇文章 0 订阅
6 篇文章 1 订阅

Bean 生命周期

之前的文章《Spring IOC 中循环依赖,两幅图搞定》中介绍了 bean 的创建过程:

1. 创建 createBean

2. populateBean

3. initializeBean

第一步,通过反射拿到构造方法创建 bean; 第二步,填充 bean 的属性,如果发现被依赖的属性不存在则会首先创建被依赖属性,然后填充,里面涉及的循环依赖的问题已经讲过;第三步初始化是我们今天来聊的话题。先看代码:

	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 {
            // 1. 调用 Aware 方法
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
            // 2. 初始化前:调用 BeanPostProcessor 方法
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
            // 3. 初始化
			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()) {
            // 4. 初始化后:调用 BeanPostProcessor 方法
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

invokeAwareMethods

初始化 bean 的第一步是调用 Aware 接口的方法, 如果 bean 实现了 Aware 接口就执行对应的方法:

	private void invokeAwareMethods(final String beanName, final Object bean) {
		// bean 是否实现 Aware 接口
        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 接口可以用来从容器自动获取一些常见的基础依赖,比如设置 beanName、context、classLoader 等, 常见的 Aware 接口:

BeanPostProcessor

这里的接口是 BeanPostProcessor,字面意思 Bean 的后置处理器,也就是 beanFactory 的钩子,允许在 bean 创建后以及初始化前后来修改 bean:

尤其注意的是在如果使用了AOP ,会在 applyBeanPostProcessorsAfterInitialization 方法中由

InfrastructureAdvisorAutoProxyCreator 生成增强对象:

invokeInitMethods

执行初始化方法,如果实现了 InitializingBean 接口,则执行 afterPropertiesSet 方法,如果有 init 方法则执行 init 方法:

	protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {
        // 是否实现了 InitializingBean 接口
		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 {
				((InitializingBean) bean).afterPropertiesSet();
			}
		}
        // 找 initMethod 并执行,可以通过 @Bean(initMethod = "") 或者 bean 标签 init-method 指定
		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);
			}
		}
	}

总结

bean 初始化过程中通过 spring 接口做了很多操作, Aware 接口、BeanPostProcessor 接口、BeanInitializing 接口等,每个接口的作用和常见的子接口需要大家掌握。


如果觉得还不错的话,关注、分享、在看, 原创不易,且看且珍惜~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【非典型Coder】

赏个鸡腿吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值