0


BeanFactory和ApplicationContext区别及详解

1.概述

​ Spring 框架带有两个 IOC 容器—— BeanFactoryApplicationContextBeanFactory是 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. 结论

  1. BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。
  2. ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能: a. 国际化支持 b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties” c. 事件传递:通过实现ApplicationContextAware接口。
  3. 常用的获取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>
标签: java spring BeanFactory

本文转载自: https://blog.csdn.net/loli_kong/article/details/124809154
版权归原作者 loli_kong 所有, 如有侵权,请联系我们删除。

“BeanFactory和ApplicationContext区别及详解”的评论:

还没有评论