1.概述
Spring 框架带有两个 IOC 容器—— BeanFactory和ApplicationContext。BeanFactory是 IOC 容器的最基本版本,ApplicationContext扩展了BeanFactory的特性。
Spring容器最基本的接口就是BeanFactory。BeanFactory负责配置、创建、管理Bean,它有一个子接口ApplicationContext,也被称为Spring上下文,容器同时还管理着Bean和Bean之间的依赖关系。
spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,DefaultListableBeanFactory 是整个spring ioc的始祖。
1.1BeanFactory
接口介绍
1.BeanFactory接口:
是Spring bean容器的根接口,提供获取bean,是否包含bean,是否单例与原型,获取bean类型,bean 别名的方法 。它最主要的方法就是getBean(String beanName)。
2.BeanFactory的三个子接口:
- HierarchicalBeanFactory:提供父容器的访问功能
- ListableBeanFactory:提供了批量获取Bean的方法
- AutowireCapableBeanFactory:在BeanFactory基础上实现对已存在实例的管理3.ConfigurableBeanFactory: 主要单例bean的注册,生成实例,以及统计单例bean4.ConfigurableListableBeanFactory: 继承了上述的所有接口,增加了其他功能:比如类加载器,类型转化,属性编辑器,BeanPostProcessor,作用域,bean定义,处理bean依赖关系, bean如何销毁…5.实现类DefaultListableBeanFactory详细介绍: 实现了ConfigurableListableBeanFactory,实现上述BeanFactory所有功能。它还可以注册BeanDefinition 接口详细介绍请参考:揭秘BeanFactory
接口具体说明
1、BeanFactory作为一个主接口不继承任何接口,暂且称为一级接口。
2、有3个子接口继承了它,进行功能上的增强。这3个子接口称为二级接口。
3、ConfigurableBeanFactory可以被称为三级接口,对二级接口HierarchicalBeanFactory进行了再次增强,它还继承了另一个外来的接口SingletonBeanRegistry
4、ConfigurableListableBeanFactory是一个更强大的接口,继承了上述的所有接口,无所不包,称为四级接口。(这4级接口是BeanFactory的基本接口体系。继续,下面是继承关系的2个抽象类和2个实现类)
5、AbstractBeanFactory作为一个抽象类,实现了三级接口ConfigurableBeanFactory大部分功能。
6、AbstractAutowireCapableBeanFactory同样是抽象类,继承自AbstractBeanFactory,并额外实现了二级接口AutowireCapableBeanFactory
7、DefaultListableBeanFactory继承自AbstractAutowireCapableBeanFactory,实现了最强大的四级接口ConfigurableListableBeanFactory,并实现了一个外来接口BeanDefinitionRegistry,它并非抽象类。
8、最后是最强大的XmlBeanFactory,继承自DefaultListableBeanFactory,重写了一些功能,使自己更强大。
1、BeanFactory作为一个主接口不继承任何接口,暂且称为一级接口。
2、有3个子接口继承了它,进行功能上的增强。这3个子接口称为二级接口。
3、ConfigurableBeanFactory可以被称为三级接口,对二级接口HierarchicalBeanFactory进行了再次增强,它还继承了另一个外来的接口SingletonBeanRegistry
4、ConfigurableListableBeanFactory是一个更强大的接口,继承了上述的所有接口,无所不包,称为四级接口。
(这4级接口是BeanFactory的基本接口体系。继续,下面是继承关系的2个抽象类和2个实现类:)
5、AbstractBeanFactory作为一个抽象类,实现了三级接口ConfigurableBeanFactory大部分功能。
6、AbstractAutowireCapableBeanFactory同样是抽象类,继承自AbstractBeanFactory,并额外实现了二级接口AutowireCapableBeanFactory
7、DefaultListableBeanFactory继承自AbstractAutowireCapableBeanFactory,实现了最强大的四级接口ConfigurableListableBeanFactory,并实现了一个外来接口BeanDefinitionRegistry,它并非抽象类。
8、最后是最强大的XmlBeanFactory,继承自DefaultListableBeanFactory,重写了一些功能,使自己更强大。
源码说明
publicinterfaceBeanFactory{/**
* 用来引用一个实例,或把它和工厂产生的Bean区分开,就是说,如果一个FactoryBean的名字为a,那么,&a会得到那个Factory
*/String FACTORY_BEAN_PREFIX ="&";/*
* 四个不同形式的getBean方法,获取实例
*/ObjectgetBean(String name)throwsBeansException;<T>TgetBean(String name,Class<T> requiredType)throwsBeansException;<T>TgetBean(Class<T> requiredType)throwsBeansException;ObjectgetBean(String name,Object... args)throwsBeansException;// 根据名称判断bean是否存在booleancontainsBean(String name);// 是否为单实例BeanbooleanisSingleton(String name)throwsNoSuchBeanDefinitionException;// 是否为原型(多实例)booleanisPrototype(String name)throwsNoSuchBeanDefinitionException;// 名称、类型是否匹配booleanisTypeMatch(String name,Class<?> targetType)throwsNoSuchBeanDefinitionException;// 获取类型Class<?>getType(String name)throwsNoSuchBeanDefinitionException;// 根据实例的名字获取实例的别名String[]getAliases(String name);}
2.延迟加载与立即加载
BeanFactory按需加载 bean,而ApplicationContext在启动时加载所有 bean。
因此, BeanFactory与**ApplicationContext相比是轻量级的。例子如下:
2.1.使用BeanFactory延迟加载
假设我们有一个名为Student的单例 bean类,它有一个方法:
publicclassStudent{publicstaticboolean isBeanInstantiated =false;publicvoidpostConstruct(){setBeanInstantiated(true);}//standard setters and getters}
我们将 在BeanFactory配置文件ioc-container-difference-example.xml中将*postConstruct()*方法定义为init-method:
<beanid="student"class="com.baeldung.ioccontainer.bean.Student"init-method="postConstruct"/>
现在,让我们编写一个测试用例,创建一个BeanFactory来检查它是否加载了Student bean:
@TestpublicvoidwhenBFInitialized_thenStudentNotInitialized(){Resource res =newClassPathResource("ioc-container-difference-example.xml");BeanFactory factory =newXmlBeanFactory(res);assertFalse(Student.isBeanInstantiated());}
在这里,Student对象没有被初始化。换句话说,只有BeanFactory被初始化。只有当我们显式调用getBean()方法时,我们的BeanFactory中定义的 bean才会被加载。
让我们检查一下我们手动调用getBean()方法的Student bean的初始化:
@TestpublicvoidwhenBFInitialized_thenStudentInitialized(){Resource res =newClassPathResource("ioc-container-difference-example.xml");BeanFactory factory =newXmlBeanFactory(res);Student student =(Student) factory.getBean("student");assertTrue(Student.isBeanInstantiated());}
在这里,Student bean 加载成功。因此,BeanFactory仅在需要时才加载 bean。
2.2. 使用ApplicationContext预加载
现在,让我们使用ApplicationContext代替BeanFactory。
我们将只定义ApplicationContext,它会通过使用立即加载策略立即加载所有 bean:
@TestpublicvoidwhenAppContInitialized_thenStudentInitialized(){ApplicationContext context =newClassPathXmlApplicationContext("ioc-container-difference-example.xml");assertTrue(Student.isBeanInstantiated());}
在这里,即使我们没有调用getBean()方法,也会创建Student对象。
ApplicationContext被认为是一个沉重的 IOC 容器,因为它的预先加载策略会在启动时加载所有 bean。相比之下, BeanFactory是轻量级的,可以在内存受限的系统中使用。尽管如此,我们最常用的仍是ApplicationContext。
3.ApplicationContext
ApplicationContext以更加面向框架的风格增强了BeanFactory,并提供了一些适用于企业应用程序的特性。
- 默认初始化所有的Singleton,也可以通过配置取消预初始化。
- 继承MessageSource,因此支持国际化。
- 资源访问,比如访问URL和文件。
- 事件传播特性,即支持aop特性。
- 同时加载多个配置文件。
- 以声明式方式启动并创建Spring容器。
ApplicationContext:是IOC容器另一个重要接口, 它继承了BeanFactory的基本功能, 同时也继承了容器的高级功能,如:MessageSource(国际化资源接口)、ResourceLoader(资源加载接口)、ApplicationEventPublisher(应用事件发布接口)等。
4. BeanFactoryPostProcessor和BeanPostProcessor的自动注册
ApplicationContext在启动时会自动注册BeanFactoryPostProcessor和****BeanPostProcessor 。另一方面,BeanFactory不会自动注册这些接口。
4.1.在BeanFactory中注册
为了理解,让我们编写两个类。
首先,我们有CustomBeanFactoryPostProcessor类,它实现了BeanFactoryPostProcessor:
publicclassCustomBeanFactoryPostProcessorimplementsBeanFactoryPostProcessor{privatestaticboolean isBeanFactoryPostProcessorRegistered =false;@OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){setBeanFactoryPostProcessorRegistered(true);}// standard setters and getters}
在这里,我们重写了postProcessBeanFactory() 方法来检查它的注册。
其次,我们有另一个类CustomBeanPostProcessor,它实现了BeanPostProcessor:
publicclassCustomBeanPostProcessorimplementsBeanPostProcessor{privatestaticboolean isBeanPostProcessorRegistered =false;@OverridepublicObjectpostProcessBeforeInitialization(Object bean,String beanName){setBeanPostProcessorRegistered(true);return bean;}//standard setters and getters}
在这里,我们重写了postProcessBeforeInitialization()方法来检查它的注册。
此外,我们在ioc-container-difference-example.xml配置文件中配置了这两个类:
<beanid="customBeanPostProcessor"class="com.baeldung.ioccontainer.bean.CustomBeanPostProcessor"/><beanid="customBeanFactoryPostProcessor"class="com.baeldung.ioccontainer.bean.CustomBeanFactoryPostProcessor"/>
让我们看一个测试用例来检查这两个类是否在启动时自动注册:
@TestpublicvoidwhenBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically(){Resource res =newClassPathResource("ioc-container-difference-example.xml");ConfigurableListableBeanFactory factory =newXmlBeanFactory(res);assertFalse(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());assertFalse(CustomBeanPostProcessor.isBeanPostProcessorRegistered());}
从我们的测试中可以看出,自动注册没有发生。
现在,让我们看一个在BeanFactory中手动添加它们的测试用例:
@TestpublicvoidwhenBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue(){Resource res =newClassPathResource("ioc-container-difference-example.xml");ConfigurableListableBeanFactory factory =newXmlBeanFactory(res);CustomBeanFactoryPostProcessor beanFactoryPostProcessor
=newCustomBeanFactoryPostProcessor();
beanFactoryPostProcessor.postProcessBeanFactory(factory);assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());CustomBeanPostProcessor beanPostProcessor =newCustomBeanPostProcessor();
factory.addBeanPostProcessor(beanPostProcessor);Student student =(Student) factory.getBean("student");assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());}
在这里,我们使用postProcessBeanFactory()方法注册CustomBeanFactoryPostProcessor和addBeanPostProcessor()方法注册CustomBeanPostProcessor。在这种情况下,他们俩都成功注册。
4.2. 在ApplicationContext中注册
正如我们前面提到的,ApplicationContext会自动注册这两个类,而无需编写额外的代码。
让我们在单元测试中验证此行为:
@TestpublicvoidwhenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically(){ApplicationContext context
=newClassPathXmlApplicationContext("ioc-container-difference-example.xml");assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());}
如我们所见,在这种情况下,两个类的自动注册都是成功的。
因此,始终建议使用ApplicationContext,因为 Spring 2.0(及更高版本)大量使用BeanPostProcessor。
还值得注意的是,如果您使用的是普通的BeanFactory,那么事务和 AOP 等功能将不会生效(至少在不编写额外代码行的情况下不会生效)。这可能会导致混淆,因为配置看起来没有任何问题。
5. 结论
- BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。
- ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能: a. 国际化支持 b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties” c. 事件传递:通过实现ApplicationContextAware接口。
- 常用的获取ApplicationContext
FileSystemXmlApplicationContext:从文件系统或者url指定的xml配置文件创建,参数为配置文件名或文件名数组,有相对路径与绝对路径。
ApplicationContext factory=new FileSystemXmlApplicationContext("src/applicationContext.xml");
ApplicationContext factory=new FileSystemXmlApplicationContext("E:/Workspaces/MyEclipse 8.5/Hello/src/applicationContext.xml");
ClassPathXmlApplicationContext:从classpath的xml配置文件创建,可以从jar包中读取配置文件。ClassPathXmlApplicationContext 编译路径总有三种方式:
ApplicationContext factory = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
ApplicationContext factory = new ClassPathXmlApplicationContext("file:E:/Workspaces/MyEclipse 8.5/Hello/src/applicationContext.xml");
XmlWebApplicationContext:从web应用的根目录读取配置文件,需要先在web.xml中配置,可以配置监听器或者servlet来实现
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
或
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
这两种方式都默认配置文件为web-inf/applicationContext.xml,也可使用context-param指定配置文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/myApplicationContext.xml</param-value>
</context-param>
版权归原作者 loli_kong 所有, 如有侵权,请联系我们删除。