思考,输出,沉淀。用通俗的语言陈述技术,让自己和他人都有所收获。
作者:毅航😜
IOC(Inverse of Control,控制反转)可以说是Spring中的核心设计理念之一,其出现的目的在于降低组件之间的耦合度,从而提高代码的可维护性和可测试性。
而IOC容器作为Spring框架的核心组件之一,其负责管理应用程序中bean的对象生命周期和依赖关系。为此Spring内部提供复杂的容器架构来完成这一功能,这也就导致了Spring中容器有下图所示的错综复杂的体系结构。

注:本篇重点对
Spring容器中的顶层接口:HierarchicalBeanFactory、ListableBeanFactory、AutowireCapableBeanFactory进行分析介绍。
面对如此复杂的结构初学者可能会感到茫然无措。如果你也有相同的疑惑,不妨跟着笔者的思路来重新梳理Spring中IOC容器间关系,理清Spring中的容器体系,体会Spring中IOC的设计精髓。
(注:不了解IOC相关知识的读者可参考笔者之前文章:深入探究控制反转(IOC)与依赖注入(DI)间的关系) 进行了解 )
万物之始------BeanFactory
结合一开始的UML类图不难看出,在Spring中所有的容器都会扩展于BeanFactory这个顶层接口。依据设计模式的中的单一职责原则来看:一个类或模块应该有且仅有一个引起它变化的原因。
换句话说,一个类或模块应该只负责一种类型的任务或功能。这也就意味着一个类或模块应该专注于完成特定的功能,而不应该承担过多的责任。
因此BeanFactory作为IOC容器的顶层接口,其所负责实现的功能应该是最简单。明确了这点后,我们来看BeanFactory的相关源码也就会变的豁然开朗。
java
public interface BeanFactory {
/**
* 获取bean信息
**/
Object getBean(String name) throws BeansException;
// ... 省略getBean各类重载方法
/**
* 检测bean是否存在于容器
**/
boolean containsBean(String name);
/**
* 判断bean的类型信息
**/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
/**
* 获取bean的别名信息
**/
String[] getAliases(String name);
}
不难发现,BeanFactory接口中定义的IOC容器的基本行为包括:Bean实例获取、判断Bean是否存在、Bean别名获取等行为。总的来看,BeanFactory接口是Spring框架中IOC容器的核心接口之一,它负责管理和控制应用程序中的对象,从而定义了IOC和DI的核心功能。
进一步,通过BeanFactory开发人员可以轻松地管理和维护应用程序中的各种组件,从而提高了代码的可维护性和可测试性。
枚举Bean实例------ListableBeanFactory
在Spring中ListableBeanFactory 继承自 BeanFactory接口,因此其除了扩展了BeanFactory基本的功能外,其还提供了更强大的检索和操作Bean的功能。
换句话,ListableBeanFactory 提供了检索Bean对象更多方式,让我们在获取Bean时,不再拘泥于BeanFactroy中getBean(String name)通过beanName获取Bean实例的方式,而是提供了按类型、名称模式、注解等条件批量检索 Bean的方式。其内部相关源码如下:
java
public interface ListableBeanFactory extends BeanFactory {
// 省略一些同名重载方法
/**
* 按类型获取 Bean 实例
***/
String[] getBeanNamesForType(ResolvableType type);
/**
* 获取所有 Bean 的名称
***/
String[] getBeanDefinitionNames();
/**
* 按注解获取 Bean 实例
***/
String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
例如,如果想获取容器中所有类型为UserService类型的Bean的名称,代码可写成如下形式:
java
// 构建上下文环境
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 获取工厂
ListableBeanFactory factory = (ListableBeanFactory) context;
// 调用ListableBeanFactory中的getBeanNamesForType方法
String[] serviceBeanNames = factory.getBeanNamesForType(UserService.class);
// 循环打印
for (String beanName : allBeanNames) {
System.out.println("Bean name: " + beanName);
}
容器间的继承------HierarchicalBeanFactory
在google翻译中Hierarchical一词被解释为:"分层的、等级的"的含义。而在Spring框架中,HierarchicalBeanFactory提供了一种维护Bean工厂间父子关系的机制。即每个 HierarchicalBeanFactory 可以有一个父工厂,同时也可以作为其他工厂的父工厂。其内部方法也比较简洁:
java
public interface HierarchicalBeanFactory extends BeanFactory {
@Nullable
BeanFactory getParentBeanFactory();
boolean containsLocalBean(String name);
}
其中,getParentBeanFactory()的作用在于获取当前容器的父BeanFactory对象;而方法 containsLocalBean(String name) 则用于检查当前本地的容器中是否有指定名称的 Bean ,而不会往上找父 BeanFactory 。该方法要与我们熟知的getBean进行区分,对于getBean而言,其会首先从当前 BeanFactory 开始查找是否存在指定的 Bean ,如果当前找不到就依次向上找父 BeanFactory 直到找到为止返回,如果找不到则会抛出 NoSuchBeanDefinitionException的相关异常。
这里不妨思考一个问题:
HierarchicalBeanFactory可以使得容器间产生继承关系,假如现在有两个容器A和B,其中容器A为B的父容器,那么容器A和容器B中是否可以有重名的Bean实例呢?欢迎评论区留下你的想法~~~
总之,HierarchicalBeanFactory 提供了一种灵活的机制来管理 bean 工厂之间的父子关系,并允许在这种分层结构中共享配置、资源和bean定义。
自动装配的基石------AutowireCapableBeanFactory
在Spring中,AutowireCapableBeanFactory 提供了 Bean实例自动装配(Autowiring)的核心功能。其允许对现有的Bean实例进行自动装配,注入其依赖。
此外,它还支持调用 Bean的初始化和销毁方法,以及应用 BeanPostProcessor 进行自定义的前后处理。
java
public interface AutowireCapableBeanFactory extends BeanFactory {
// 省略其他内部属性即重名重载方法
// 对现有的 Bean 实例进行自动装配。
void autowireBean(Object existingBean)
// 创建一个新的 Bean 实例,并自动装配其依赖。
<T> T createBean(Class<T> beanClass)
// 配置现有的 Bean 实例,包括自动装配和应用后置处理器。
Object configureBean(Object existingBean, String beanName)
// 初始化现有的 Bean 实例,包括调用初始化方法和后置处理器
void initializeBean(Object existingBean, String beanName)
// 销毁现有的 Bean 实例,包括调用销毁方法和后置处理器。
void destroyBean(Object existingBean, String beanName)
}
接下来,我们便通过一个例子来演示如何通过AutowireCapableBeanFactory来完成自动装配,开始之前我们先定义如下UserMapper、UserService两个类,其依赖关系如下所示:
java
public class UserMapper {
public void doSomething() {
System.out.println("Doing something in MyRepository");
}
}
public class UserService {
@Autowired
private UserMapper userMapper;
public void performAction() {
userMapper.doSomething();
}
}
(注:此时省略UserMapper、UserService的beans.xml的配置信息)
java
// 加载 Spring 配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 获取 AutowireCapableBeanFactory
AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory();
// 对现有 Bean 实例进行自动装配
UserService userService = new UserService();
factory.autowireBean(existingBean);
在上述代码中,通过 autowireBean 方法,UserService 实例的 userMapper 字段将会被自动注入一个 UserMapper 实例,从而可以正确调用 performAction 方法。
总的来看,AutowireCapableBeanFactory 提供了灵活的自动装配和Bean管理功能,使你可以在运行时动态地创建和配置 Bean 实例,并自动注入它们的依赖。
总结
本文从BeanFactory入手,详细的对Spring容器中的顶层接口:HierarchicalBeanFactory、ListableBeanFactory、AutowireCapableBeanFactory进行分析介绍。具体来看
HierarchicalBeanFactory:支持父子Bean工厂的层次结构,允许在父工厂中查找Bean。ListableBeanFactory:提供批量检索和查询Bean的功能,支持按类型和注解查找Bean。AutowireCapableBeanFactory:提供自动装配和Bean生命周期管理功能,支持动态创建和配置Bean。