BeanFactory接口体系整理
BeanFactory体系结构
BeanFactory
BeanFactory作为Spring容器的顶层接口,那么它的作用一定是最简单,最核心的,特性如下:
- 基础的容器
- 定义了作用域的概念
- 集成了环境配置
- 支持多种类型的配资源
- 层次性的设计(父子结构)
- 完整的生命周期控制机制
Javadoc
BeanFactory是Spring中管理Bean的容器,它是Spring容器的顶层接口,它的子类都是为了扩展实现某些额外的特性,如:层次性(HierarchicalBeanFactory),可搜索性(ListableBeanFactory),可配置性(ConfigurableBeanFactory)等;
BeanFactory是所有程序组件的注册中心,所有的Bean最终都会在BeanFactory中创建和保存,另外,BeanFactory还集成了应用程序组件的配置;
一般来说更好是通过setter方法或构造器注入的方式使用依赖注入,而不是通过如BeanFactory进行依赖查找的方式;
通常情况下,BeanFactory会加载存储在配资源中的BeanDefinition,并使用org.springframework.beans包中的API来配置bean;Spring可以支持的配置源类型(LDAP,RDBMS,XML,Properties等)有多种;
BeanFactory可以支持父子结构,父子结构由HierarchicalBeanFactory实现;如果BeanFactory实例中没有找到指定的Bean,则会向父工厂搜索查找,BeanFactory实例中的Bean应该覆盖任何父工厂中的同名Bean;
BeanFactory接口实现了尽可能支持标准Bean的生命周期接口;
BeanFactory的子接口
HierarchicalBeanFactory
HierarchicalBeanFactory从类名可以体现它是层次性的BeanFactory,它是由BeanFactory实现的子接口,可以在ConfigurableBeanFactory接口中找到用于BeanFactory的相应setParentBeanFactory方法,该方法允许以可配置的方式设置父工厂;
Javadoc
在该接口中有两个方法,一个是getParentBeanFactory方法,它可以用于获取父BeanFactory对象;另一个是containLocalBean方法,它是用于检查当前本地的容器是否有指定的Bean,而不会往上找父BeanFactory;
如果当前的BeanFactory中有指定的Bean,父BeanFactory是有可能存在指定的相同类型的Bean,测试如下:
查看代码
public class BeanFactoryDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
parent.registerBean(BeanA.class);
parent.refresh();
child.registerBean(BeanA.class);
child.setParent(parent);
child.refresh();
System.out.println("child BeanA:" + child.getBean(BeanA.class));
System.out.println("parent BeanA:" + parent.getBean(BeanA.class));
}
static class BeanA {
}
}
ListableBeanFactory
Javadoc
查看代码
public class BeanA {
}
查看代码
public class BeanB {
}
查看代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="beanA" class="org.example.bean.BeanA"/>
</beans>
查看代码
public class ListableBeanFactoryDemo {
public static void main(String[] args) {
ClassPathResource resource = new ClassPathResource("bean.xml");
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.loadBeanDefinitions(resource);
// 打印容器中的所有Bean
System.out.print("加载xml文件后容器中的Bean:");
Stream.of(beanFactory.getBeanDefinitionNames()).forEach(System.out::println);
// 手动注册一个单实例Bean
beanFactory.registerSingleton("beanB", new BeanB());
// 再打印容器中的所有Bean
System.out.print("手动注册单实例Bean后容器中的所有Bean:");
Stream.of(beanFactory.getBeanDefinitionNames()).forEach(System.out::println);
}
}
查看代码
System.out.println("容器中的所有BeanB Name:" + Arrays.toString(beanFactory.getBeanNamesForType(BeanB.class)));
System.out.println("容器中的所有BeanB Type:" + beanFactory.getBeansOfType(BeanB.class));
AutowireCapableBeanFactory
Javadoc
ConfigurableBeanFactory
ConfigurableBeanFactory是具备可配置的BeanFactory;一个类的属性设置为private属性后,提供的getter方法表示该属性可读,提供的setter方法方法表示该属性是可写的,在Spring的BeanFactory也是这样的,普通的BeanFactory只有get相关的操作,而Configurable开头的BeanFactory或Application则具备了set相关的操作;
Javadoc
大多数BeanFactory的实现类都会实现这个可配置的接口,除了BeanFactory接口中的基本获取方法外,还提供了配置BeanFactory的功能;
ConfigurableBeanFactory提供了可配置的功能,可以调用它里面定义的方法对BeanFactory进行修改,扩展操作;
ConfigurationBeanFactory接口并不推荐开发者在应用程序编码中使用,而是推荐使用BeanFactory或ListableBeanFactory;ConfigurationBeanFactory仅用于允许在框架内部进行即插即用,并允许对BeanFactory中的配置方法的特殊访问;
程序在运行期间不应该对BeanFactory再进行频繁的变动,此时应该只有读的操作,而不应该出现写的操作;Spring不希望开发者用ConfiguationBeanFactory,取而代之的是使用BeanFactory;
BeanFactory的实现
AbstractBeanFactory
AbstractBeanFactory是BeanFactory最基本的抽象实现,作为一个抽象类,只具备了一部分功能,不是完整的实现;
Javadoc
它是BeanFactory接口最基础的抽象实现类,提供ConfigurableBeanFactory SPI的全部功能,并且它可以从配置源(XML,LDAP,RDBMS等)获取BeanDefinition;
SPI全称是Service Provider Interface,它是JDK内置的一种服务提供发现的机制,不过在Spring中它有自己的一套实现;
此类可以提供单例Bean的缓存(通过其父类DefaultSingletonBeanRegistry),单例/原型Bean 的决定,FactoryBean 处理,Bean的别名,用于合并子BeanDefinition的BeanDefinition并以及Bean销毁(DisposableBean接口,自定义destroy方法);此外,它可以通过实现HierarchicalBeanFactory接口来管理BeanFactory层次结构(在未知 bean 的情况下委托给父工厂);
子类要实现主要模板方法是getBeanDefinition和createBean,分别为给定的Bean名称检索BeanDefinition,根据给定的BeanDefinition创建Bean实例,这些操作的默认实现可以在在DefaultListableBeanFactory和AbstractAutowireCapableBeanFactory中找到;
Spring中大量使用模板方法模式来设计核心组件,父类提供逻辑规范,子类提供具体步骤的实现;
AbstractAutowireCapableBeanFactory
AbstractAutowireCapableBeanFactory是AutowireCapableBeanFactory接口的实现,它可以实现组件的自动注入;
Javadoc
AbstractAutowireCapableBeanFactory集成了AbstractBeanFactory抽象类,还额外实现了AutowireCapbleBeanFactory接口,那实现了这个接口表示可以实现自动注入;此外,AbstractAutowireCapableBeanFactory还实现了AbstractBeanFactory的createBean方法,createBean方法不是最终实现Bean创建的逻辑,只是说具备了创建Bean的功能;而另一个方法doCreateBean,它才是真正执行创建Bean的逻辑,它同样是在AbstractAutowireCapableBeanFactory中定义,并且它是protected方法,没有子类重写它;
AbstractAutowireCapableBeanFactory跟AbstractBeanFactory不太一样的,AbstractAutowireCapableBeanFactory是没有把全部模板方法都实现,它保留了resolveDependency方法,这个方法的作用是解析Bean的成员中定义的属性依赖关系;
DefaultListableBeanFactory
DefaultListableBeanFactory这个类是唯一一个目前使用的BeanFactory的实现;
Javadoc
DefaultListableBeanFactory是Spring的ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的默认实现,它是基于BeanDefinition的BeanFactory实现,可以通过后置处理器进行扩展;
特定的BeanDefinition格式的解释器通常是单独实现的,而不是作为BeanFactory的子类实现;
ListableBeanFactory的替代实现StaticListableBeanFactory,它实现起来相对简单,功能比较单一;
它只能管理单例的Bean,没有BeanDefinition等概念;
XmlBeanFactory
在Spring 3.1后,XmlBeanFactory正式被标注为过时,替代的方案是使用DefaultListableBeanFactory + XmlBeanDefinitionReader,这种设计更符合组件的单一职责原则,另外从Spring 3.0后出现了注解驱动的IOC容器,XML驱动的方式不应该单独成为一种方案,而是使用一个通用的容器,通过组合它来实现,这样可以实现配置源载体分离;
ApplicationContext
ApplicationContext是Spring最核心的接口,它继承了ListableBeanFactory,HierarchicalBeanFactory,ResourcePatternResolver,MessageSource,ApplicationEventPublisher,Environment,因此间接继承了BeanFactory;
Javadoc
ApplicationContext是为应用程序配置的接口,在应用程序运行时,它是只读的,如果它的实现支持,它可以重新加载;
- 用于访问应用程序组件的Bean工厂方法,继承自ListableBeanFactory接口;
- 以通用方式加载文件资源的能力,继承自ResourceLoader接口;
- 能够将事件发布给注册的监听器,继承自ApplicationEventPublisher接口;
- 解析消息的能力,支持国际化,继承自MessageSource接口;
- 从父context继承,在子容器中的定义将始终优先;例如,整个Web应用程序都可以使用单个父context,而每个servlet 都有其自己的子context,该子context独立于任何其他servlet的context;
Application是支持层级结构的,文档中描述的是父子context,context不仅包含容器,还包含动态增强,资源加载,事件监听机制等扩展功能,而容器只负责管理Bean实例;
ApplicationContext除了标准的BeanFactory生命周期外,它还实现了检测并调用ApplicationContextAware,以及ResourceLoader,ApplicationEventPublisherAware和MessageSourceAware;
其中,ApplicationContext间接继承了ResourceLoader,ApplicationEventPublisher,MessageSource,而xxxAware接口的作用是将Spring的xxx组件依赖注入到实现了Aware接口的对象实例中,最终调用这些xxxAware接口注入的是ApplicationContext本身;
ApplicationContext的子接口
ConfigurableApplicationContext
ConfigurableApplicationContext给ApplicatinContext提供了可配置的功能,实现了ConfigurableApplicationContext该接口的实现类可以被客户端代码修改内部某些配置;
Javadoc
ApplicationContext的扩展接口
EnvironmentCapable
在Spring中,以Capable结尾的接口,通常可以通过这个接口的某个特定方法(通常是getxxx方法)拿到特定的组件;
org.springframework.context.ConfigurableApplicationContext#getEnvironment
MessageSource
Javadoc
- ResourceBundleMessageSource:建立在标准 java.util.ResourceBundle 之上,共享其局限性;
- ReloadableResourceBundleMessageSource:高度可配置,尤其是在重新加载消息定义方面;
ApplicationEventPublisher
ApplicationEventPublisher它是事件发布器;
Javadoc
ApplicationEventPublisher是封装事件发布功能的接口,它作为ApplicationContext的父接口;
Spring内部支持很强大的事件监听机制,而ApplicationContext作为容器的最顶级,需要实现观察者模式中发布器;
ResoucePatternResolver
ResoucePatternResolver从类名可以解释为资源模式解析器,它是根据特定的路径去解析资源文件;
Javadoc
ResoucePatternResolver是ResourceLoader的扩展,可以检查传入的ResourceLoader是否实现了此扩展接口,ResouceLoader实现最基本的解析,ResoucePatternResolver可以支持Ant形式的带星号(*)的路径解析;
ResoucePatternResolver是一个独立的实现,可在ApplicationContext外部使用,ResourceArrayPropertyEditor使用它来填充Resource数组中Bean属性;
- /WEB-INF/*.xml:匹配 /WEB-INF 目录下的任意 xml 文件
- /WEB-INF/**/beans-*.xml:匹配 /WEB-INF 下面任意层级目录的 beans- 开头的 xml 文件
- /**/*.xml:匹配任意 xml 文件
ApplicationContext的实现类
AbstractApplicationContext
AbstractApplicationContext定义了绝大部分的应用上下文的特性和功能;
Javadoc
ApplicationContext接口的抽象实现,不强制用于配置的存储类型;简单地实现通用上下文功能,使用模板方法模式,需要具体的子类来实现抽象方法;
注:AbstractApplicationContext中定义了一个控制ApplicationContext生命周期的核心方法,AbstractApplicationContext#refresh;
GenericApplicationContext
GenericApplicationContext是一个普通类,非抽象类,它是ApplicationContext的通用实现,它里面具备了ApplicationContext基本的功能;
Javadoc
注:GenericApplicationContext内部中维护了一个DefaultListableBeanFactory实例,ApplicationContext与BeanFactory之间存在的不是继承关系,而是组合关系;
大致意思:由于GenericApplicationContext中组合了一个DefaultListableBeanFactory,而这个BeanFactory是在GenericApplicationContext的构造方法中就已经初始化了,那么初始化好的 BeanFactory就不允许在运行期间被重复刷新了;
BeanFactory刷新逻辑如下:
org.springframework.context.support.GenericApplicationContext#refreshBeanFactory
AbstractRefreshableApplicationContext
AbstractRefreshableApplicationContext与GenericApplicationContext最大区别之一是AbstractRefreshableApplicationContext可以被重复刷新;
Javadoc
AbstractXmlApplicationContext
AbstractXmlApplicationContext是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext的直接父类;
Javadoc
AbstractXmlApplicationContext根据不同子类(ClassPathXmlApplicationContext,FileSystemXmlApplicationContext)的实现,通过重写getResourceByPath或getResourcePatternResolver方法,选择不同的配置文件方式加载;
org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.xml.XmlBeanDefinitionReader)
如果使用的是ClassPathXmlApplicationContext,ClassPathXmlApplicationContext则重写getConfigResources方法;
如果使用的是FileSystemXmlApplicationContext,FileSystemXmlApplicationContext则重写getConfigLocations方法;
ClassPathXmlApplicationContext
ClassPathXmlApplicationContext是从classpath下加载XML配置文件的ApplicationContext;
Javadoc
ClassPathXmlApplicationContext是独立的基于 XML 的 ApplicationContext,它从classpath中获取配置文件,将纯路径解释为包含包路径的classpath资源名称(例如 mypackage / myresource.txt );
ClassPathXmlApplicationContext可以通过重写getConfigLocations方法来调整配置文件默认读取的位置,加载配置文件的方式还可以使用Ant模式匹配;
AnnotationConfigApplicationContext
AnnotationConfigApplicationContext继承了GenericApplicationContext,因此它只能刷新一次;