mini-spring 学习笔记—IoC

最近在学习 mini-spring 项目,记录笔记以总结心得

AOP篇:mini-spring 学习笔记—AOP

扩展篇:mini-spring 学习笔记—扩展篇

高级篇:mini-spring 学习笔记—高级篇

最简单的 bean 容器

这一章实现了一个最简单的 bean 容器 BeanFactory

BeanFactory 中使用 Map 对 bean 名字和实例进行了映射,这样可以通过 bean 的名称获取 bean 实例

public class BeanFactory {
	private Map<String, Object> beanMap = new HashMap<>();

	public void registerBean(String name, Object bean) {
		beanMap.put(name, bean);
	}

	public Object getBean(String name) {
		return beanMap.get(name);
	}
}

BeanDefinition 和 BeanDefinitionRegistry

这一章的代码量一下子就多了起来,具体多了哪些文件可以看作者的提交记录“BeanDefinition和注册表”,修订号为27c3a1e859bbb3bb21b2250a68cc0f69d159e75b

让我们慢慢分析

BeanDefinition

主要内容就在 beanClass 这个属性上,它存储了这个 bean 的类型

private Class beanClass;

BeanDefinitionRegistry 和 DefaultListableBeanFactory

本章新增了 BeanDefinitionRegistry 接口,主要方法为 registerBeanDefinition。用于将 bean 定义添加进 bean 的注册表中

void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);

它的一个实现为 DefaultListableBeanFactory 类,它使用 Map 对 bean 的名称和 bean 定义做映射。

private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

当有 bean 要进行注册的时候,便调用 registerBeanDefinition 方法,将 bean 名称和 bean 定义放入到 beanDefinitionMap 中。

// BeanDefinitionRegistry 接口的实现
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
	beanDefinitionMap.put(beanName, beanDefinition);
}

DefaultSingletonBeanRegistry

DefaultSingletonBeanRegistry 实现了 SingletonBeanRegistry 接口,主要作用为使用 Map 管理单例 bean。

private Map<String, Object> singletonObjects = new HashMap<>();

AbstractBeanFactory 是其子类,对 getBean 方法进行了重写。

@Override
public Object getBean(String name) throws BeansException {
	Object bean = getSingleton(name);
	if (bean != null) {
		return bean;
	}

	BeanDefinition beanDefinition = getBeanDefinition(name);
	return createBean(name, beanDefinition);
}

getBeanDefinitioncreateBean 是这个类的两个虚方法,由子类 AbstractAutowireCapableBeanFactory 实现

AbstractAutowireCapableBeanFactory

这个类是比较重要的一个类,继承了 AbstractBeanFactory 类,它的作用是根据 bean 名称和 bean 定义,将 bean 进行实例化,最重要的方法是 doCreateBean

protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
	Class beanClass = beanDefinition.getBeanClass();
	Object bean = null;
	try {
		bean = beanClass.newInstance();
	} catch (Exception e) {
		throw new BeansException("Instantiation of bean failed", e);
	}

	addSingleton(beanName, bean);
	return bean;
}

直接使用 newInstance 方法进行实例化,并使用 addSingleton 添加进管理单例 bean 的 singletonObjects Map 中。

本章小结

本章比较重要的类和接口为为:

  • AbstractAutowireCapableBeanFactory 类,完成 bean 的实例化工作
  • BeanDefinitionRegistry 接口,完成 bean 定义的方法规范工作

现阶段关系图如下

image

注意画红圈的部分,DefaultListableBeanFactory 继承和实现了 AbstractAutowireCapableBeanFactoryBeanDefinitionRegistry,表示这个 bean 容器同时具有了注册 bean 和实例化 bean 的功能。

Bean 实例化策略 InstantiationStrategy

InstantiationStrategy

该接口规范了 bean 的初始化方法,实现类有两个:CglibSubclassingInstantiationStrategySimpleInstantiationStrategy

SimpleInstantiationStrategy 和 CglibSubclassingInstantiationStrategy

SimpleInstantiationStrategy

SimpleInstantiationStrategy 实现了 instantiate 方法,使用无参构造函数初始化。

// 根据 bean 的无参构造函数实例化
public Object instantiate(BeanDefinition beanDefinition) throws BeansException {
	Class beanClass = beanDefinition.getBeanClass();
	try {
		// 获取 bean 类型的无参构造函数
		Constructor constructor = beanClass.getDeclaredConstructor();
		// 调用 Bean 的无参构造函数实例化
		return constructor.newInstance();
	} catch (Exception e) {
		throw new BeansException("Failed to instantiate [" + beanClass.getName() + "]", e);
	}
}

CglibSubclassingInstantiationStrategy

先简要介绍一下什么是 CGLIB

CGLIB(Code Generation Library)是一个用于生成字节码并创建动态代理对象的第三方库,它通过生成目标类的子类(继承目标类)来实现动态代理。子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用。

比如需要通过 CGLIB 生成一个类 A,则 CGLIB 会生成一个子类 B extends A 并返回 B

它的 instantiate 方法实现如下

public Object instantiate(BeanDefinition beanDefinition) throws BeansException {
	// 创建代理对象
	Enhancer enhancer = new Enhancer();
	// 设置代理类的父类
	// 即,生成的代理类是 beanDefinition.getBeanClass() 的子类
	// 该子类是目标类的扩展,它继承了目标类的所有非final方法和属性
	enhancer.setSuperclass(beanDefinition.getBeanClass());
	// 设置回调函数
	// obj: 这是被增强的对象,即代理对象,它正在被拦截。
	// method: 这是表示正在调用的方法的 Method 对象。
	// argsTemp: 这是一个对象数组,表示传递给方法的参数。
	// proxy: 这是对代理对象本身的引用。
	// proxy.invokeSuper(obj, argsTemp): 这一行调用了父类(原始类)的原始方法,
	// 传递了原始的参数。它本质上是将方法调用委托给了原始类的方法。
	// 这是 CGLIB 动态代理的关键步骤之一,允许在调用原始方法之前和之后执行自定义逻辑。
	enhancer.setCallback((MethodInterceptor)(obj, method, argsTemp, proxy) -> proxy.invokeSuper(obj, argsTemp));
	// 返回实例
	return enhancer.create();
}

AbstractAutowireCapableBeanFactory

AbstractAutowireCapableBeanFactory 添加了 instantiationStrategy 属性,用于存储当前容器所用的 bean 实例化策略。由此, AbstractAutowireCapableBeanFactory 类不再显式实例化 bean,而是交给了 InstantiationStrategy 进行实例化。

// doCreateBean 方法
bean = createBeanInstance(beanDefinition);
protected Object createBeanInstance(BeanDefinition beanDefinition) {
	return getInstantiationStrategy().instantiate(beanDefinition);
}

为 bean 填充属性

PropertyValue 和 PropertyValues

PropertyValue 类用于存储属性名属性值

// 属性名
private final String name;
// 属性值
private final Object value;

PropertyValues 类实现了对 PropertyValue 的存储、添加和获取操作。

它使用 List 进行存储

private final List<PropertyValue> propertyValueList = new ArrayList<>();

使用遍历查找的方式根据属性名查找属性值

public PropertyValue getPropertyValue(String propertyName) {
	for (int i = 0; i < this.propertyValueList.size(); i++) {
		PropertyValue pv = this.propertyValueList.get(i);
		if (pv.getName().equals(propertyName)) {
			return pv;
		}
	}
	return null;
}

BeanDefinition 和 AbstractAutowireCapableBeanFactory

BeanDefinition 增添了属性 propertyValues 用于存储 bean 的属性值

AbstractAutowireCapableBeanFactory 添加了 applyPropertyValues 方法,在 bean 实例化后为 bean 的属性赋值

// doCreateBean 方法
bean = createBeanInstance(beanDefinition);
//为bean填充属性
applyPropertyValues(beanName, bean, beanDefinition);
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
	try {
		for (PropertyValue propertyValue : beanDefinition.getPropertyValues().getPropertyValues()) {
			String name = propertyValue.getName();
			Object value = propertyValue.getValue();
			//通过反射设置属性
			BeanUtil.setFieldValue(bean, name, value);
		}
	} catch (Exception ex) {
		throw new BeansException("Error setting property values for bean: " + beanName, ex);
	}
}

为 bean 注入 bean

BeanReference

BeanReference 类用于存储所包含的 bean 名称

private final String beanName;

AbstractAutowireCapableBeanFactory

增添先对依赖 bean 进行实例化的代码

String name = propertyValue.getName();
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
	// beanA依赖beanB,先实例化beanB
	BeanReference beanReference = (BeanReference) value;
	value = getBean(beanReference.getBeanName());
}

资源和资源加载器

这里以 classpath 资源的加载为例进行说明,其他两种资源的加载方法也大同小异。

Resource 和 ResourceLoader

Resource 接口用于对资源的抽象和访问进行规范。

ResourceLoader 接口为资源加载器接口,对资源加载的方法进行规范。

ClassPathResource 和 DefaultResourceLoader

ClassPathResource 实现了 Resource 接口,存储了资源所在的路径

private final String path;

实现了 getInputStream 方法,通过存储的资源路径生成资源的输入流,然后返回这个输入流。

public InputStream getInputStream() throws IOException {
	InputStream is = this.getClass().getClassLoader().getResourceAsStream(this.path);
	if (is == null) {
		throw new FileNotFoundException(this.path + " cannot be opened because it does not exist");
	}
	return is;
}

DefaultResourceLoader 实现了 ResourceLoader 接口,实现了 getResource 方法,完成了获取资源的功能。

在获取资源过程中,使用变量存储路径前缀,用于判断是否是 classpath 资源。

public static final String CLASSPATH_URL_PREFIX = "classpath:";
public Resource getResource(String location) {
	if (location.startsWith(CLASSPATH_URL_PREFIX)) {
		//classpath下的资源
		return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()));
	} else {
		try {
			//尝试当成url来处理
			URL url = new URL(location);
			return new UrlResource(url);
		} catch (MalformedURLException ex) {
			//当成文件系统下的资源处理
			return new FileSystemResource(location);
		}
	}
}

在 xml 文件中定义 bean

BeanDefinitionReader 和 AbstractBeanDefinitionReader

BeanDefinitionReader 接口规范了读取 bean 定义信息并注册 bean的行为

AbstractBeanDefinitionReader 抽象类主要实现了重载方法 loadBeanDefinitions 方法中的一个方法

public void loadBeanDefinitions(String[] locations) throws BeansException {
	for (String location : locations) {
		loadBeanDefinitions(location);
	}
}

这里通过遍历所有的资源路径,调用 XmlBeanDefinitionReader 中的方法实现对 xml 文件的读取和其中 bean 的注册

XmlBeanDefinitionReader

XmlBeanDefinitionReader 继承自 AbstractBeanDefinitionReader,作用为对 xml 文件的读取和其中 bean 的注册,主要方法为 loadBeanDefinitionsdoLoadBeanDefinitions

loadBeanDefinitions 方法为重载方法,首先使用资源加载器 resourceLoader 获取 xml,在通过输入流读取 xml。

public void loadBeanDefinitions(String location) throws BeansException {
	ResourceLoader resourceLoader = getResourceLoader();
	Resource resource = resourceLoader.getResource(location);
	loadBeanDefinitions(resource);
}
InputStream inputStream = resource.getInputStream();
...
doLoadBeanDefinitions(inputStream);

doLoadBeanDefinitions 实现了从输入流读取内容,并在读取结束后为 bean 进行注册。

protected void doLoadBeanDefinitions(InputStream inputStream) {
	// 获取 XML 文档
	Document document = XmlUtil.readXML(inputStream);
	Element root = document.getDocumentElement();
	NodeList childNodes = root.getChildNodes();
	...
	if (getRegistry().containsBeanDefinition(beanName)) {
		//beanName不能重名
		throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
	}
	//注册BeanDefinition
	getRegistry().registerBeanDefinition(beanName, beanDefinition);

BeanFactoryPostProcessor 和 BeanPostProcessor

本章是 IoC 中最重要的两章之一(另一个是下一章的 ApplicationContext),理解了本章和下一章,基本就理解了 spring 的核心原理。

PropertyValues

增加了使用新属性值覆盖原有属性值的代码

public void addPropertyValue(PropertyValue pv) {
	// 遍历每一个属性
	for (int i = 0; i < this.propertyValueList.size(); i++) {
		PropertyValue currentPv = this.propertyValueList.get(i);
		if (currentPv.getName().equals(pv.getName())) {
			//覆盖原有的属性值
			this.propertyValueList.set(i, pv);
			return;
		}
	}
	// 如果没有这项属性,就添加属性
	this.propertyValueList.add(pv);
}

BeanFactoryPostProcessor 和 CustomBeanFactoryPostProcessor

BeanFactoryPostProcessor 接口规范了bean 定义加载完成后但实例化之前修改 bean 属性值的方法

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

CustomBeanFactoryPostProcessor 实现了 BeanFactoryPostProcessor 接口,完成了实例化前修改 bean 属性值的功能

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	// 获取 bean 信息
	BeanDefinition personBeanDefiniton = beanFactory.getBeanDefinition("person");
	// 获取 bean 属性值
	PropertyValues propertyValues = personBeanDefiniton.getPropertyValues();
	// 将person的name属性改为ivy
	propertyValues.addPropertyValue(new PropertyValue("name", "ivy"));
}

BeanPostProcessor 和 CustomerBeanPostProcessor

BeanPostProcessor 接口规范了bean 实例化后,初始化前后需要执行的方法

// 在bean执行初始化方法之前执行此方法
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
// 在bean执行初始化方法之后执行此方法
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

CustomerBeanPostProcessor 类实现了 BeanPostProcessor 接口,完成了初始化前后执行的方法内容。

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("CustomerBeanPostProcessor#postProcessBeforeInitialization");
	// 换 person 名字
	if("person".equals(beanName)){
		((Person) bean).setName("ameameame");
	}
	//换兰博基尼
	if ("car".equals(beanName)) {
		((Car) bean).setBrand("lamborghini");
	}
	return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	System.out.println("CustomerBeanPostProcessor#postProcessAfterInitialization");
	return bean;
}

ConfigurableBeanFactory

ConfigurableBeanFactory 接口规范了可配置的 bean 工厂(容器) 的方法,实现了这个接口就表示这个容器可以进行自定义配置。

AbstractBeanFactory 和 AbstractAutowireCapableBeanFactory

AbstractBeanFactory 类增加了 beanPostProcessors 属性,用于存放该容器的 BeanPostProcessor,同时增加了 addBeanPostProcessor 方法对其进行添加和覆盖

private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
	//有则覆盖
	this.beanPostProcessors.remove(beanPostProcessor);
	this.beanPostProcessors.add(beanPostProcessor);
}

AbstractAutowireCapableBeanFactory 类继承自 AbstractBeanFactory,新增了对 bean 实例化后,初始化前后的处理代码

首先在创建完 bean 实例且填充完 bean 属性后,执行 bean 的初始化

// doCreateBean 方法
bean = createBeanInstance(beanDefinition);
//为bean填充属性
applyPropertyValues(beanName, bean, beanDefinition);
//执行bean的初始化方法和BeanPostProcessor的前置和后置处理方法
bean = initializeBean(beanName, bean, beanDefinition);

initializeBean 方法中,使用容器中配置的 BeanPostProcessor 对象进行处理

// initializeBean 方法
// 执行BeanPostProcessor的前置处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
invokeInitMethods(beanName, wrappedBean, beanDefinition);
// 执行BeanPostProcessor的后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

前置处理方法 applyBeanPostProcessorsBeforeInitialization 中,遍历每一个 BeanPostProcessor 对象,即遍历每一个处理方法,执行相应的处理

// applyBeanPostProcessorsBeforeInitialization 方法
Object result = existingBean;
// 遍历每一项处理措施
for (BeanPostProcessor processor : getBeanPostProcessors()) {
	Object current = processor.postProcessBeforeInitialization(result, beanName);
	if (current == null) {
		return result;
	}
	result = current;
}
return result;

后置处理方法 applyBeanPostProcessorsAfterInitialization 中,与前置处理方法相同,也是遍历每一个处理项目,执行相应的处理

// applyBeanPostProcessorsAfterInitialization 方法
Object result = existingBean;
// 遍历每一项处理措施
for (BeanPostProcessor processor : getBeanPostProcessors()) {
	Object current = processor.postProcessAfterInitialization(result, beanName);
	if (current == null) {
		return result;
	}
	result = current;
}
return result;

应用上下文 ApplicationContext

本章为理解 spring 核心原理的第二章

应用上下文 ApplicationContext是spring 中较之于 BeanFactory 更为先进的IOC容器, ApplicationContext 除了拥有 BeanFactory 的所有功能外,还支持特殊类型 bean 如上一 节中的 BeanFactoryPostProcessor 和 BeanPostProcessor 的自动识别、资源加载、容器事件和监听器、国际化支持、单例bean自动初始化等。

AbstractApplicationContext

AbstractApplicationContext 类包含一个容器 beanFactory

private DefaultListableBeanFactory beanFactory;

同时,AbstractApplicationContext 实现了 ConfigurableApplicationContext 接口中的 refresh 方法

refresh 方法

refresh方法是本章最核心的方法,它用于刷新容器,承载了从加载 bean 到实例化 bean 的所有操作

public void refresh() throws BeansException {
	//创建BeanFactory,并加载BeanDefinition
	refreshBeanFactory();
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	//在bean实例化之前,执行BeanFactoryPostProcessor
	invokeBeanFactoryPostProcessors(beanFactory);
	//BeanPostProcessor需要提前与其他bean实例化之前注册
	registerBeanPostProcessors(beanFactory);
	//提前实例化单例bean
	beanFactory.preInstantiateSingletons();
}

refreshBeanFactory 方法

refreshBeanFactory 方法实现于 AbstractRefreshableApplicationContext 类中

protected final void refreshBeanFactory() throws BeansException {
	// 创建 bean 工厂
	DefaultListableBeanFactory beanFactory = createBeanFactory();
	// 加载 bean 定义
	loadBeanDefinitions(beanFactory);
	this.beanFactory = beanFactory;
}
protected DefaultListableBeanFactory createBeanFactory() {
	return new DefaultListableBeanFactory();
}

接下来执行 loadBeanDefinitions 方法,为 AbstractRefreshableApplicationContext 的接口方法,实现位于 AbstractXmlApplicationContext 类中,根据 configLocations 从 xml 文件加载 bean 定义

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory, this);
	String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		beanDefinitionReader.loadBeanDefinitions(configLocations);
	}
}

invokeBeanFactoryPostProcessors 方法

用于执行 bean 实例化之前的 BeanFactoryPostProcessor 对象处理

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
	for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
		beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
	}
}

首先来看第一行代码

Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);

getBeansOfType 方法,用于获取所有以 type 为父类的或者实现 type 接口的 bean 定义

public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
	Map<String, T> result = new HashMap<>();
	// 遍历所有 bean 定义
	beanDefinitionMap.forEach((beanName, beanDefinition) -> {
		// 获取 bean 类型
		Class beanClass = beanDefinition.getBeanClass();
		// type 类型能否由 beanClass 类型转换而来
		// 即 beanClass 类型是否是 type 类型的子类或子接口
		if (type.isAssignableFrom(beanClass)) {
			T bean = (T) getBean(beanName);
			result.put(beanName, bean);
		}
	});
	return result;
}

之后回到 invokeBeanFactoryPostProcessors 方法,执行下面的 for 循环

for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
	beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}

这个 for 循环为当前容器调用了多个 beanFactoryPostProcessor 接口的 postProcessBeanFactory 方法。在章中,postProcessBeanFactory 方法只有一个实现,位于 CustomBeanFactoryPostProcessor 类中。

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	System.out.println("CustomBeanFactoryPostProcessor#postProcessBeanFactory");
	BeanDefinition personBeanDefiniton = beanFactory.getBeanDefinition("person");
	PropertyValues propertyValues = personBeanDefiniton.getPropertyValues();
	//将person的name属性改为ivy
	propertyValues.addPropertyValue(new PropertyValue("name", "ivy"));
}

在实际项目中,可能会有多个 postProcessBeanFactory 的实现和多个 BeanFactory 的实现,所以需要使用遍历调用接口方法的方式,以此统一地完成对容器的修改

registerBeanPostProcessors 方法

该方法用于对 BeanPostProcessor 对象进行注册,也就是添加到一个 List

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
	for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
		beanFactory.addBeanPostProcessor(beanPostProcessor);
	}
}

preInstantiateSingletons 方法

提前实例化所有的单例 bean,底层实现在 DefaultListableBeanFactory 类中

public void preInstantiateSingletons() throws BeansException {
	beanDefinitionMap.keySet().forEach(this::getBean);
}

实际就是为 Map 中的每个 bean 定义执行 getBean 方法

至此,本章最核心的 refresh 方法已经讲完了,接下来就是在怎样调用 refresh 方法,本章中是在 ClassPathXmlApplicationContext 类进行调用。

ClassPathXmlApplicationContext

该类通过带参数的构造函数接收 configLocations,也就是 classpath 资源的路径,之后调用 refresh 函数

public ClassPathXmlApplicationContext(String[] configLocations) throws BeansException {
	this.configLocations = configLocations;
	refresh();
}

本章小结

此时 bean 的生命周期如下

image

bean 的初始化和销毁方法

BeanDefinition 和 ConfigurableBeanFactory

BeanDefinition 类中添加了两个属性

  • String initMethodName:用于记录 bean 的初始化方法名字
  • String destroyMethodName:用于记录 bean 的销毁方法名字

InitializingBean 和 DisposableBean

InitializingBean 接口规范了 bean 的初始化行为

void afterPropertiesSet() throws Exception;

DisposableBean 接口规范了 bean 的销毁行为

void destroy() throws Exception;

这两个接口都需要 bean 类来实现,来表明这个 bean 是有自己的初始化或销毁方法

public class Person implements InitializingBean, DisposableBean {
	...
	public void afterPropertiesSet() {...}
	public void destroy() {...}
	...
}

同时 bean 也需要定义自己的初始化和销毁方法

// Person 类
public void customInitMethod() {...}
public void customDestroyMethod() {...}

为什么一个 bean 要有两套初始化和销毁方法呢?

我觉得 afterPropertiesSetdestroy 是供容器调用的接口,是面向容器的。而 customInitMethodcustomDestroyMethod 是面向 bean 本身的。

DefaultSingletonBeanRegistry

该类是用来存储实例化之后的单例 bean,本章新增了一个 Map 类型的变量 disposableBeans 专门用于存储有销毁方法的单例 bean。同时新增方法 registerDisposableBean 对可销毁的 bean 进行注册,注意,这里注册的 bean 其实是代理类

public void registerDisposableBean(String beanName, DisposableBean bean) {
	disposableBeans.put(beanName, bean);
}

destroySingletons 方法用于销毁所有可销毁的单例 bean

public void destroySingletons() {
	ArrayList<String> beanNames = new ArrayList<>(disposableBeans.keySet());
	// 遍历每一个具有销毁方法的 bean
	for (String beanName : beanNames) {
		DisposableBean disposableBean = disposableBeans.remove(beanName);
		try {
			disposableBean.destroy();
		} catch (Exception e) {
			throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
		}
	}
}

这里通过调用所有 bean 的 destroy 方法完成 bean 的销毁,看到这里应该对我上文提到的 destroy 方法是面向容器有更深的理解

AbstractAutowireCapableBeanFactory

bean 的初始化是在实例化之后进行的,在 AbstractAutowireCapableBeanFactory 类的 doCreateBean 方法内的 initializeBean 调用中进行初始化,initializeBean 方法实现如下

protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
	//执行BeanPostProcessor的前置处理
	Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
	try {
		invokeInitMethods(beanName, wrappedBean, beanDefinition);
	} catch (Throwable ex) {
		throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", ex);
	}
	//执行BeanPostProcessor的后置处理
	wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
	return wrappedBean;
}

它会调用 invokeInitMethods 方法执行 bean 的初始化

protected void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Throwable {
	if (bean instanceof InitializingBean) {
		((InitializingBean) bean).afterPropertiesSet();
	}
	String initMethodName = beanDefinition.getInitMethodName();
	if (StrUtil.isNotEmpty(initMethodName)) {
		Method initMethod = ClassUtil.getPublicMethod(beanDefinition.getBeanClass(), initMethodName);
		if (initMethod == null) {
			throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
		}
		initMethod.invoke(bean);
	}
}

先执行 bean 的 afterPropertiesSet 方法,然后通过反射获取到 bean 的初始化方法 initMethod,使用 initMethod.invoke(bean) 完成 initMethod 对 bean 的作用。

在创建并初始化完 bean 实例之后,需要注册有销毁方法的 bean,通过调用 registerDisposableBeanIfNecessary 函数实现。

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
	// bean 继承自 DisposableBean 或有自定义的销毁方法
	if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
		registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
	}
}

这里调用的是 DefaultSingletonBeanRegistry 类的 registerDisposableBean 方法,不过传入的参数是 DisposableBeanAdapter 类型,对 bean 做了一次代理。

DisposableBeanAdapter

该类是对可销毁 bean 的代理类,有三个属性

private final Object bean;
private final String beanName;
private final String destroyMethodName;

包含一个 destroy 方法

public void destroy() throws Exception {
	if (bean instanceof DisposableBean) {
		((DisposableBean) bean).destroy();
	}
	// 避免同时继承自 DisposableBean,且自定义方法与 DisposableBean 方法同名,销毁方法执行两次的情况
	if (StrUtil.isNotEmpty(destroyMethodName) && !(bean instanceof DisposableBean && "destroy".equals(this.destroyMethodName))) {
		// 执行自定义方法
		Method destroyMethod = ClassUtil.getPublicMethod(bean.getClass(), destroyMethodName);
		if (destroyMethod == null) {
			throw new BeansException("Couldn't find a destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'");
		}
		destroyMethod.invoke(bean);
	}
}

AbstractApplicationContext

对 bean 进行销毁的时候,需要调用 AbstractApplicationContextregisterShutdownHook 方法

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:init-and-destroy-method.xml");
...
applicationContext.registerShutdownHook();  //或者手动关闭 applicationContext.close();
public void registerShutdownHook() {
	Thread shutdownHook = new Thread() {
		public void run() {
			doClose();
		}
	};
	// Runtime.getRuntime() 返回当前 Java 虚拟机的运行时对象。
	// addShutdownHook(Thread shutdownHook) 是运行时对象的方法之一,用于向虚拟机注册一个在 JVM 关闭时执行的线程(也称为关闭钩子)。
	Runtime.getRuntime().addShutdownHook(shutdownHook);
}

向 JVM 传入一个钩子线程 shutdownHook,线程的 run 方法执行 doClose,经过一系列传导,最终调用容器类的 destroySingletons 方法,销毁所有的 bean。

protected void doClose() { destroyBeans(); }
protected void destroyBeans() { getBeanFactory().destroySingletons(); }

本章小结

此时 bean 的生命周期如下

image

Aware 接口

这里作者在 log 里一直在说“感知”这个词,一直不理解什么意思,看了代码才明白,“感知”就是指bean 能知道它所属的 factory 和ApplicationContext(即容器)

Aware、BeanFactoryAware 和 ApplicationContextAware

Aware 接口是标记类接口,实现了该接口的 bean 便能够感知容器,有两个子接口 BeanFactoryAwareApplicationContextAware,分别规范了 setBeanFactory 方法和 setApplicationContext 方法

void setBeanFactory(BeanFactory beanFactory) throws BeansException;
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

HelloService

一个 bean 如果要感知容器,需要实现 Aware 接口或其子接口

public class HelloService implements ApplicationContextAware, BeanFactoryAware

HelloService 还添加了两个属性,用于存储容器类,只有实现了 Aware 的子接口,才能对两个容器类进行 set 操作

private ApplicationContext applicationContext;
private BeanFactory beanFactory;

AbstractAutowireCapableBeanFactory

在初始化 bean 的时候(即调用 initializeBean 方法的时候),对工厂类容器进行 set

// initializeBean 方法
if (bean instanceof BeanFactoryAware) {
	((BeanFactoryAware) bean).setBeanFactory(this);
}

ApplicationContextAwareProcessor

实现 ApplicationContextAware 的接口感知 ApplicationContext, 是通过 BeanPostProcessor 接口实现的

// refresh 方法
//添加ApplicationContextAwareProcessor,让继承自ApplicationContextAware的bean能感知bean
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

ApplicationContextAwareProcessor 类实现了 BeanPostProcessor 接口。包含变量 applicationContext 用于记录上下文容器。同时重写了 postProcessBeforeInitialization 用于执行 bean 自己的初始化方法前,为 bean 设置上下文容器

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	// 如果 bean 实现了 ApplicationContextAware 接口
	if (bean instanceof ApplicationContextAware) {
		// 让 bean 存储它所属的是哪一个 ApplicationContext
		((ApplicationContextAware) bean).setApplicationContext(applicationContext);
	}
	return bean;
}

设置上下文容器发生的时机,与设置工程容器的时机相同,也是在调用 initializeBean 方法的时候进行设置(即执行 BeanPostProcessor 的前置处理的时候)

// initializeBean
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

本章小结

至此,bean 的生命周期如下

image

bean 作用域,增加 prototype 的支持

先对 prototype 和 singleton 做一个区别解释

如果一个bean是prototype的,并且这个bean要被注入到其它bean或者你通过getBean这样的方式获得这个bean的时候,spring容器会创建一个新的实例给你。

singleton模式指的是对某个对象的完全共享,包括代码空间和数据空间,也就是说,singleton会让所有线程共享他的成员变量。prototype则不会这样。

BeanDefinition

bean 定义中增加了多个对作用域进行判断的属性,默认 bean 是 singleton 的

// BeanDefinition 类
public static String SCOPE_SINGLETON = "singleton";
public static String SCOPE_PROTOTYPE = "prototype";
private String scope = SCOPE_SINGLETON;
private boolean singleton = true;
private boolean prototype = false;

AbstractAutowireCapableBeanFactory

doCreateBean 方法中对 bean 的作用域进行判断,如果不是单例 bean,就不往 singletonObjects 中加入该 bean。这样会导致单例 bean 的容器中永远没有该 bean,这样每次 getBean 的时候,都会重新创建一个 bean

// doCreateBean 方法
if (beanDefinition.isSingleton()) {
	addSingleton(beanName, bean);
}

使用作者提供的测试程序,在 getSingleton 方法中打印 singletonObjects 的元素个数,会发现一直是0,也证明作用域为 prototype 的 bean 不会被添加进 singletonObjects 容器中

image

并且在 registerDisposableBeanIfNecessary 方法内注册 bean 的销毁方法时,只会给单例 bean 注册销毁方法,因为单例 bean 只有一个,可以根据 bean 名称直接获取

if (beanDefinition.isSingleton()) {
	if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
		registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
	}
}

DefaultListableBeanFactory

因为从 xml 文件读取注册 bean 定义的时候,没有对 bean 的作用域进行判断,将所有的 bean 定义存储在了同一个 Map 中,所以在 preInstantiateSingletons 实例化单例 bean 的时候,要对 bean 定义中的作用域进行判断

public void preInstantiateSingletons() throws BeansException {
	beanDefinitionMap.forEach((beanName, beanDefinition) -> {
		if(beanDefinition.isSingleton()){
			getBean(beanName);
		}
	});
}

本章小结

此时。bean 的生命周期如下

image

FactoryBean

FactoryBean 是一种特殊的 bean,当向容器获取该 bean 时,容器不是返回其本身,而是返回其 getObject 方法的返回值,可通过编码方式定义复杂的 bean

FactoryBean 和 CarFactoryBean

FactoryBean 是一个接口,实现了这个接口就可以生产单一类型的 bean。它规范了两个方法

T getObject() throws Exception;
boolean isSingleton();

CarFactoryBean 实现了 FactoryBean 接口,它包含了 Car 这个类型的 bean 所具有的属性

private String brand;

实现了 getObject 方法,用于生产一个 Car bean

public Car getObject() throws Exception {
	// 深拷贝
	Car car = new Car();
	car.setBrand(brand);
	return car;
}

AbstractBeanFactory

增加了一个容器 factoryBeanObjectCache 用于存储工厂 bean 生产出来的单例 bean

private final Map<String, Object> factoryBeanObjectCache = new HashMap<>();

增加了方法 getObjectForBeanInstance

protected Object getObjectForBeanInstance(Object beanInstance, String beanName) {
	Object object = beanInstance;
	if (beanInstance instanceof FactoryBean) {
		FactoryBean factoryBean = (FactoryBean) beanInstance;
		try {
			if (factoryBean.isSingleton()) {
				//singleton作用域bean,从缓存中获取
				object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					object = factoryBean.getObject();
					this.factoryBeanObjectCache.put(beanName, object);
				}
			} else {
				//prototype作用域bean,新创建bean
				object = factoryBean.getObject();
			}
		} catch (Exception ex) {
			throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", ex);
		}
	}
	return object;
}

容器事件和事件监听器

容器监听器的作用就是当一个对象被修改时,会自动通知它的依赖对象

ApplicationEvent 和 ApplicationContextEvent

该类继承自 EventObject,仅有一个带参构造函数。本章中,所有自己写的事件类都需要继承该类。

public ApplicationEvent(Object source) { super(source); }

本章中写的事件类有 CustomEventContextRefreshedEventContextClosedEventApplicationContextEvent,这里仅对 ApplicationContextEvent 进行详细说明

public abstract class ApplicationContextEvent extends ApplicationEvent {
	public ApplicationContextEvent(ApplicationContext source) { super(source); }
	public final ApplicationContext getApplicationContext() { return (ApplicationContext) getSource(); }
}

ApplicationContextEvent 仅有两个方法,一个是带参构造函数,另一个用于返回上下文容器

ApplicationListener

ApplicationListener 为事件监听者接口,是一个泛型接口,用于监听 ApplicationEvent 及其子类的事件。仅有 onApplicationEvent 一个方法,用于传入事件进行处理

void onApplicationEvent(E event);

本章中有 ContextClosedEventListenerContextRefreshedEventListenerCustomEventListener 三个监听者类实现了此接口

ApplicationEventMulticaster 及其实现

ApplicationEventMulticaster 是事件广播接口,规范了事件广播类的行为。它有三个方法,分别用于添加监听者、删除监听者、广播事件

void addApplicationListener(ApplicationListener<?> listener);
void removeApplicationListener(ApplicationListener<?> listener);
void multicastEvent(ApplicationEvent event);

AbstractApplicationEventMulticasterApplicationEventMulticaster 的一个实现。它使用 Set 保存监听者,同时能感知工厂容器

public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new HashSet<>();
private BeanFactory beanFactory;

实现了添加与删除监听者的行为方法

public void addApplicationListener(ApplicationListener<?> listener) {
	applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
}
public void removeApplicationListener(ApplicationListener<?> listener) {
	applicationListeners.remove(listener);
}

SimpleApplicationEventMulticasterAbstractApplicationEventMulticaster 的子类,实现了广播方法,通过轮询集合的方式将事件广播

public void multicastEvent(ApplicationEvent event) {
	// 遍历每一个监听者
	for (ApplicationListener<ApplicationEvent> applicationListener : applicationListeners) {
		// 这个监听器是否对这个事件感兴趣
		if (supportsEvent(applicationListener, event)) {
			// 处理事件
			applicationListener.onApplicationEvent(event);
		}
	}
}

supportsEvent 方法用于判断监听者是否支持处理该事件

protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
	// 调用 getGenericInterfaces() 方法获取实现的泛型接口的数组
	Type type = applicationListener.getClass().getGenericInterfaces()[0];
	//
	Type actualTypeArgument = ((ParameterizedType) type).getActualTypeArguments()[0];
	String className = actualTypeArgument.getTypeName();
	Class<?> eventClassName;
	try {
		eventClassName = Class.forName(className);
	} catch (ClassNotFoundException e) {
		throw new BeansException("wrong event class name: " + className);
	}
	return eventClassName.isAssignableFrom(event.getClass());
}

AbstractApplicationContext

增添了变量 applicationEventMulticaster 用于广播事件

private ApplicationEventMulticaster applicationEventMulticaster;

refresh 方法中新增了几个行为

// refresh 方法
...
//初始化事件发布者
initApplicationEventMulticaster();
//注册事件监听器
registerListeners();
...
//发布容器刷新完成事件
finishRefresh();

initApplicationEventMulticaster 方法

初始化事件广播者

protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
	beanFactory.addSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
}

registerListeners 方法

向事件广播者注册事件监听者

protected void registerListeners() {
	Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
	for (ApplicationListener applicationListener : applicationListeners) {
		applicationEventMulticaster.addApplicationListener(applicationListener);
	}
}

finishRefresh 方法

发布容器刷新完成事件

protected void finishRefresh() {
	publishEvent(new ContextRefreshedEvent(this));
}

委托广播类广播此事件

public void publishEvent(ApplicationEvent event) {
	// 广播类来广播事件
	applicationEventMulticaster.multicastEvent(event);
}
posted @ 2023-11-21 16:25  Frodo1124  阅读(188)  评论(0编辑  收藏  举报