详解Spring中IOC容器的顶层接口
点击关注公众号,“技术干货”及时达!
?思考,输出,沉淀。用通俗的语言陈述技术,让自己和他人都有所收获。
作者:毅航??
?「IOC(Inverse of Control,控制反转)可以说是Spring中的核心设计理念之一,其出现的目的在于降低组件之间的耦合度,从而提高代码的可维护性和可测试性。」
而IOC容器作为Spring框架的核心组件之一,其负责管理应用程序中bean的对象生命周期和依赖关系。为此Spring内部提供复杂的容器架构来完成这一功能,这也就导致了Spring中容器有下图所示的错综复杂的体系结构。
?注:本篇重点对Spring容器中的顶层接口:HierarchicalBeanFactory、ListableBeanFactory、AutowireCapableBeanFactory进行分析介绍。
?面对如此复杂的结构初学者可能会感到茫然无措。如果你也有相同的疑惑,不妨跟着笔者的思路来重新梳理Spring中IOC容器间关系,理清Spring中的容器体系,体会Spring中IOC的设计精髓。
(注:不了解IOC相关知识的读者可参考笔者之前文章:深入探究控制反转(IOC)与依赖注入(DI)间的关系)(https://juejin.cn/post/7355740605274177547) 进行了解 )
万物之始——BeanFactory结合一开始的UML类图不难看出,在Spring中所有的容器都会扩展于BeanFactory这个顶层接口。依据设计模式的中的单一职责原则来看:「一个类或模块应该有且仅有一个引起它变化的原因」。
换句话说,一个类或模块应该只负责一种类型的任务或功能。「这也就意味着一个类或模块应该专注于完成特定的功能,而不应该承担过多的责任。」
因此BeanFactory作为IOC容器的顶层接口,其所负责实现的功能应该是最简单。明确了这点后,我们来看BeanFactory的相关源码也就会变的豁然开朗。
publicinterfaceBeanFactory{
/**
*获取bean信息
**/
ObjectgetBean(Stringname)throwsBeansException;
//...省略getBean各类重载方法
/**
*检测bean是否存在于容器
**/
booleancontainsBean(Stringname);
/**
*判断bean的类型信息
**/
booleanisSingleton(Stringname)throwsNoSuchBeanDefinitionException;
booleanisPrototype(Stringname)throwsNoSuchBeanDefinitionException;
booleanisTypeMatch(Stringname,ResolvableTypetypeToMatch)throwsNoSuchBeanDefinitionException;
booleanisTypeMatch(Stringname,ClasstypeToMatch)throwsNoSuchBeanDefinitionException;
/**
*获取bean的别名信息
**/
String[]getAliases(Stringname);
}
不难发现,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的方式」。其内部相关源码如下:
publicinterfaceListableBeanFactoryextendsBeanFactory{
//省略一些同名重载方法
/**
*按类型获取Bean实例
***/
String[]getBeanNamesForType(ResolvableTypetype);
/**
*获取所有Bean的名称
***/
String[]getBeanDefinitionNames();
/**
*按注解获取Bean实例
***/
String[]getBeanNamesForAnnotation(Class?extendsAnnotationannotationType);
例如,如果想获取容器中所有类型为UserService类型的Bean的名称,代码可写成如下形式:
//构建上下文环境
ApplicationContextcontext=newClassPathXmlApplicationContext("beans.xml");
//获取工厂
ListableBeanFactoryfactory=(ListableBeanFactory)context;
//调用ListableBeanFactory中的getBeanNamesForType方法
String[]serviceBeanNames=factory.getBeanNamesForType(UserService.class);
//循环打印
for(StringbeanName:allBeanNames){
System.out.println("Beanname:"+beanName);
}
容器间的继承——HierarchicalBeanFactory在google翻译中Hierarchical一词被解释为:"分层的、等级的"的含义。而在Spring框架中,HierarchicalBeanFactory提供了一种维护Bean工厂间父子关系的机制。「即每个 HierarchicalBeanFactory 可以有一个父工厂,同时也可以作为其他工厂的父工厂」。其内部方法也比较简洁:
publicinterfaceHierarchicalBeanFactoryextendsBeanFactory{
@Nullable
BeanFactorygetParentBeanFactory();
booleancontainsLocalBean(Stringname);
}
其中,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 进行自定义的前后处理。
publicinterfaceAutowireCapableBeanFactoryextendsBeanFactory{
//省略其他内部属性即重名重载方法
//对现有的 Bean 实例进行自动装配。
voidautowireBean(ObjectexistingBean)
//创建一个新的 Bean 实例,并自动装配其依赖。
TTcreateBean(ClassbeanClass)
//配置现有的 Bean 实例,包括自动装配和应用后置处理器。
ObjectconfigureBean(ObjectexistingBean,StringbeanName)
//初始化现有的Bean实例,包括调用初始化方法和后置处理器
voidinitializeBean(ObjectexistingBean,StringbeanName)
//销毁现有的 Bean 实例,包括调用销毁方法和后置处理器。
voiddestroyBean(ObjectexistingBean,StringbeanName)
}
接下来,我们便通过一个例子来演示如何通过AutowireCapableBeanFactory来完成自动装配,开始之前我们先定义如下UserMapper、UserService两个类,其依赖关系如下所示:
publicclassUserMapper{
publicvoiddoSomething(){
System.out.println("DoingsomethinginMyRepository");
}
}
publicclassUserService{
@Autowired
privateUserMapperuserMapper;
publicvoidperformAction(){
userMapper.doSomething();
}
}
(注:此时省略UserMapper、UserService的beans.xml的配置信息)
//加载Spring配置文件ApplicationContextcontext=newClassPathXmlApplicationContext("beans.xml");
//获取AutowireCapableBeanFactory
AutowireCapableBeanFactoryfactory=context.getAutowireCapableBeanFactory();
//对现有Bean实例进行自动装配
UserServiceuserService=newUserService();
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。点击关注公众号,“技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线