mini-spring 学习笔记—IoC
最近在学习 mini-spring 项目,记录笔记以总结心得
AOP篇:mini-spring 学习笔记—AOP
最简单的 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);
}
getBeanDefinition
和 createBean
是这个类的两个虚方法,由子类 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 定义的方法规范工作
现阶段关系图如下
注意画红圈的部分,DefaultListableBeanFactory
继承和实现了 AbstractAutowireCapableBeanFactory
和 BeanDefinitionRegistry
,表示这个 bean 容器同时具有了注册 bean 和实例化 bean 的功能。
Bean 实例化策略 InstantiationStrategy
InstantiationStrategy
该接口规范了 bean 的初始化方法,实现类有两个:CglibSubclassingInstantiationStrategy
和 SimpleInstantiationStrategy
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 的注册,主要方法为 loadBeanDefinitions
和 doLoadBeanDefinitions
。
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 的生命周期如下
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 要有两套初始化和销毁方法呢?
我觉得 afterPropertiesSet
和 destroy
是供容器调用的接口,是面向容器的。而 customInitMethod
和 customDestroyMethod
是面向 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 进行销毁的时候,需要调用 AbstractApplicationContext
的 registerShutdownHook
方法
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 的生命周期如下
Aware 接口
这里作者在 log 里一直在说“感知”这个词,一直不理解什么意思,看了代码才明白,“感知”就是指bean 能知道它所属的 factory 和ApplicationContext(即容器)。
Aware、BeanFactoryAware 和 ApplicationContextAware
Aware
接口是标记类接口,实现了该接口的 bean 便能够感知容器,有两个子接口 BeanFactoryAware
和 ApplicationContextAware
,分别规范了 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 的生命周期如下
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
容器中
并且在 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 的生命周期如下
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); }
本章中写的事件类有 CustomEvent
、ContextRefreshedEvent
、ContextClosedEvent
和 ApplicationContextEvent
,这里仅对 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);
本章中有 ContextClosedEventListener
、ContextRefreshedEventListener
、CustomEventListener
三个监听者类实现了此接口
ApplicationEventMulticaster 及其实现
ApplicationEventMulticaster
是事件广播接口,规范了事件广播类的行为。它有三个方法,分别用于添加监听者、删除监听者、广播事件
void addApplicationListener(ApplicationListener<?> listener);
void removeApplicationListener(ApplicationListener<?> listener);
void multicastEvent(ApplicationEvent event);
AbstractApplicationEventMulticaster
是 ApplicationEventMulticaster
的一个实现。它使用 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);
}
SimpleApplicationEventMulticaster
是 AbstractApplicationEventMulticaster
的子类,实现了广播方法,通过轮询集合的方式将事件广播
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);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」