首页 > 其他分享 >《系列二》-- 10、initialize-初始化bean

《系列二》-- 10、initialize-初始化bean

时间:2023-07-13 15:15:20浏览次数:49  
标签:10 -- beanName init mbd bean null method

目录

阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于 spring 源码 5.x 版本。

写在开始前的话:

阅读spring 源码实在是一件庞大的工作,不说全部内容,单就最基本核心部分包含的东西就需要很长时间去消化了:

  • beans
  • core
  • context

实际上我在博客里贴出来的还只是一部分内容,更多的内容,我放在了个人,fork自 spring 官方源码仓了; 而且对源码的学习,必须是要跟着实际代码层层递进的,不然只是干巴巴的文字味同嚼蜡。

https://gitee.com/bokerr/spring-framework-5.0.x-study

这个仓设置的公共仓,可以直接拉取。



Spring源码阅读系列--全局目录.md



initializeBean 方法源码如下

    /**
	 * Initialize the given bean instance, applying factory callbacks
	 * as well as init methods and bean post processors.
	 * <p>Called from {@link #createBean} for traditionally defined beans,
	 * and from {@link #initializeBean} for existing bean instances.
	 *
	 * @param beanName the bean name in the factory (for debugging purposes)
	 * @param bean     the new bean instance we may need to initialize
	 * @param mbd      the bean definition that the bean was created with
	 *                 (can also be {@code null}, if given an existing bean instance)
	 * @return the initialized bean instance (potentially wrapped)
	 * @see BeanNameAware
	 * @see BeanClassLoaderAware
	 * @see BeanFactoryAware
	 * @see #applyBeanPostProcessorsBeforeInitialization
	 * @see #invokeInitMethods
	 * @see #applyBeanPostProcessorsAfterInitialization
	 */
	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		} else {
			// 特殊 bean 处理   Aware BeanClassLoaderAware BeanFactoryAware
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// init-method 执行前   后处理器
			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()) {
			// init-method 执行后  后处理器
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

这里的操作其实相当简单

"后置处理器" 是老朋友了

二、重要操作

2.1 应用 Aware

实际上它是个接口,我们可以把它叫做自动装配。

若我们想要实现某个自动装配操作,那么就可以实现 Aware 接口并定义自定义的装配行为。

详情可以参考下边的博客:

《系列二》-- 11、Aware是什么

2.2 applyBeanPostProcessorsBeforeInitialization:

执行-bean初始化前-后置处理器: 简单的说,就是要在初始化方法(init-method) 执行前,才能进行的一些操作。
[遗憾的是,目前spring.beans 包下,除了测试包之外,spring框架中,并没有这方面的实际应用。
也就是说你可以忽略它,这个后置处理器,目前还不会对 bean 做出任何的改动。]

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

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {// 初始化 init-method 前
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

2.3 invokeInitMethods:

如果元数据中定义了init-method:结合包装器 bw,以及 BeanDefinition 中记录的元数据;
应用反射的原理,执行该 init-method.

    /**
	 * Give a bean a chance to react now all its properties are set,
	 * and a chance to know about its owning bean factory (this object).
	 * This means checking whether the bean implements InitializingBean or defines
	 * a custom init method, and invoking the necessary callback(s) if it does.
	 *
	 * @param beanName the bean name in the factory (for debugging purposes)
	 * @param bean     the new bean instance we may need to initialize
	 * @param mbd      the merged bean definition that the bean was created with
	 *                 (can also be {@code null}, if given an existing bean instance)
	 * @throws Throwable if thrown by init methods or by the invocation process
	 * @see #invokeCustomInitMethod
	 */
	protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {
		// 首先判断是否实现了 InitializingBean 接口,如果实现了,直接调用接口方法: afterPropertiesSet 即可完成初始化操作
		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 {
				// 直接回调完成操作,适用于较高版本的 spring 
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		// 低版本中,通过在xml中配置 init-method 方式实现初始化方法
		// 此种情形下,需要通过 反射调用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)) {
				// 利用反射执行  init-method
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

2.4 applyBeanPostProcessorsAfterInitialization

执行-bean初始化后-后置处理器: 简单的说,就是要在初始化方法(init-method) 执行后,才能进行的一些操作。
[遗憾的是,目前spring.beans 包下,除了测试包之外,spring框架中,并没有这方面的实际应用。
也就是说你可以忽略它,这个后置处理器,目前还不会对 bean 做出任何的改动。]

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

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			// afterInitialization: 初始化之后 - 后置处理
			Object current = processor.postProcessAfterInitialization(result, beanName);  // 初始化 init-method 之后  
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

标签:10,--,beanName,init,mbd,bean,null,method
From: https://www.cnblogs.com/bokers/p/17542742.html

相关文章

  • 《系列二》-- 9、bean属性填充
    目录一、概述:populateBean在什么时候执行?二、populateBean的重要操作三、重点操作一propertyValue的注入3.1根据Bean名称注入3.2浅看一下,获取非'简单'类型property的方法3.3根据Bean类型注入四、注入依赖的应用阅读之前要注意的东西:本文就是主打流水账式的源码阅......
  • Springboot实现注解判断权限
    Springboot实现注解判断权限今天记录一下使用springboot的注解来给方法加权限避免了每个方法都需要大量的权限判断超级好用√@目录Springboot实现注解判断权限1.创建权限注解2.定义一个权限的枚举类3.创建拦截器AOP校验权限poincut表达式介绍4.使用注解1.创建权限注解首先......
  • 华为云MetaStudio全新升级,盘古数字人大模型助力数字人自由
    摘要:基于盘古大模型能力,华为云MetaStudio数字内容生产线全新升级,推出数字人模型生成服务和模型驱动服务。近日,华为开发者大会2023(Cloud)在东莞拉开帷幕。基于盘古大模型能力,华为云MetaStudio数字内容生产线全新升级,推出数字人模型生成服务和模型驱动服务,旨在通过数字人服务......
  • 《系列二》-- 11、Aware是什么
    目录正文阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于spring源码5.x版本。写在开始前的话:阅读spring源码实在是一件庞大的工作,不说全部内容,单就最基本核心部分包含的东西就需要很长时间去消......
  • js的arguments到底是什么?
    js的arguments到底是什么?类数组对象:arguments众所周知,js是一门相当灵活的语言。当我们在js中在调用一个函数的时候,我们经常会给这个函数传递一些参数,js把传入到这个函数的全部参数存储在一个叫做arguments的东西里面,那么这到底是什么东西?在js中万物皆对象,甚至数组字符串函数都......
  • linux查看网络端口是万兆还是千兆
    1、ethtoolethtool网络接口名#ethtoolem4(网络接口名)Settingsforem4:Supportedports:[TP]Supportedlinkmodes:10baseT/Half10baseT/Full100baseT/Half100baseT/Full1000baseT/FullSupportsauto-negotiation:YesAdvertisedlinkmodes:10baseT/Half10baseT/Full1......
  • SAM(segment-anything)解读-整理中
    sam的一个很重要的作用,用来寻找关注点算法来源:meta数据集:训练数据集一共1100万张,包含11亿个mask训练gpu:256块(如果是个人特殊需求,就需要微调,而且也只能微调)sam如何获取训练集?模型评估速度: ......
  • ArrayList源码阅读
    ArrayList源码分析ArrayList简介ArrayList的底层是数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加ArrayList实例的容量。这可以减少递增式再分配的数量。ArrayList继承于AbstractList,实现......
  • 虚树 学习笔记
    虚树学习笔记引入我们在解决树上问题时,往往都是对整棵树进行处理,或者每次询问都对一个点、点对进行处理,这类题型一般都可以通过dp、树剖解决;然而,有一类问题要求我们每次对树上一些关键点进行处理。这类问题的特点就是询问次数多,而询问的点的总数不多。可如果我们每次都把整棵......
  • 学习霍夫曼编码
    霍夫曼编码广泛用于数据压缩算法,其重要性不言而喻。内容:写一个程序读ASCII文件,统计各字符的频率并制定霍夫曼编码表,最后将此文件的内容根据编码表翻译为二进制文件,计算压缩率。代码清单:#include...typedefstruct{floatweight;intparent,lc,rc;}node;#define......