BeanFactory和ApplicationContext的简单介绍

引言

Spring通过一个配置文件描述Bean及Bean之间的依赖关系,利用Java语音的反射功能实例化Bean并建立Bean之间的依赖关系。Spring的IoC容器在完成这些底层工作的基础上,还提供了Bean实例缓存、生命周期、Bean实例代理、事件发布、资源装载等服务。
Bean工厂(org.springframework.beans.factory.Beanfactory)是Spring框架最核心的接口,它提供了高级IoC的配置机制。BeanFacotry使管理不同类型的Java对象成为可能,应用上下文(org.springframework.context.ApplicationContext)建立在BeanFactory基础之上,提供了更多面向应用的功能,它提供了国际化支持和框架事件体系,更易于创建实际应用。一般我们将BeanFactory成为IoC容器,而称ApplicationContext为应用上下文,但是有时为了行文方便,也将ApplicationContext成为Spring容器。
对于二者的用途,我们可以进行简单的划分:BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都可以直接使用ApplicationContext而非底层的BeanFactory。

BeanFactory介绍

BeanFactory是一个通用的类工厂,可以创建并管理各种类的对象。这些可被创建和管理的对象仅仅是一个POJO,Spring称之为Bean。

BeanFactory的类体系结构

Spring为BeanFactory提供了多种实现,最常见的是XmlBeanFactory,但是在Spring3.2中已被废弃,建议使用XmlBeanDefinitionReader、DefaultListableBeanFactory替代。BeanFactory的类继承体系设计优雅,堪称经典。
BeanFactory接口位于类结构树的顶端,它最主要的方法就是getBean(String beanName),该方法从容器中返回特定名称的Bean。BeanFactory的功能通过其他接口得到不断扩展:

  • ListableBeanFactory:该接口定义了访问容器中Bean基本信息的若干方法,如查看Bean的个数、获取某一类型Bean的配置名、查看容器是都保罗某一个Bean等;
  • HierarchicalBeanFactory:父子级联IoC容器的接口,子容器可以通过接口方法访问父容器;
  • ConfigurableBeanFactory:这是一个重要的接口,增强了IoC容器的可定制性。它定义了设置类装载器、属性编译器、容器初始化后置处理器等方法;
  • AutowireCapableBeanFactory:定义了将容器中的Bean按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法;
  • SingletonBeanFactory:定义了允许在运行期向容器注册单实例Bean的方法;
  • BeanDefinitionRegistry:Spring配置文件中每一个节点元素在Spring容器里都通过一个BeanDfinition对象表示,它描述了Bean的配置信息。而BeanDefinitionRegistry接口提供了向容器手工注册BeanDefinition对象的方法。

ApplicationContext介绍

如果说BeanaFactory是Spring的"心脏",那么ApplicationContext就是完整的"身躯"了。ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。在BeanFactory中,很多功能需要以编程的方式实现,而在ApplicationContext中则可以通过配置方式实现。

ApplicationContext类体系结构

ApplicationContext的主要实现类是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统中装载配置文件。ApplicationContext继承了HierachicalBeanFactory和ListableBeanFactory接口,在此基础上,还通过其他接口扩展了BeanFactory的功能:

  • ApplicationEvenPublisher:让容器拥有发布应用上下文事件的功能,包括容器启动事件、关闭事件等。实现了ApplicationListener事件监听接口的Bean可以接收到容器事件,并对事件进行响应处理。在ApplicationContext抽象实现类AbstractApplicationContext中存在一个ApplicationEvent,它负责保存所有的监听器,以便在容器产生上下文事件时通知这些事件监听者;
  • MessageSource:为应用提供i18n国际化消息访问的功能;
  • ResourcePatternResolver:所有ApplicationContext实现类都实现了类似于PathMatchingResourcePatternResolver的功能,可以通过带前缀的Ant风格的资源文件路径装载Spring的配置文件;
    LifeCycle:该接口提供了start()和stop()两个方法,主要用于控制异步处理过程。在具体使用时,该接口同时被ApplicationContext实现及具体Bean实现,ApplicationContext会将start/stop的信息传递给容器中所有实现了该接口的Bean,以达到管理控制JMX、任务调度等目的。

ConfigurableApplicationContext扩展于ApplicationContext,新增了两个主要的方法:refresh()和close()方法,让ApplicationContext具有启动、刷新和关闭应用上下文的能力。在应用上下文关闭的情况下调用refresh()即可启动应用上下文,在已经启动的状态下掉哦那个refresh()则可清楚缓存并重新装载配置信息,而调用close()则可关闭应用上下文。这些接口方法为容器的控制管理带来了便利,但作为开发者,我们并不需要过多关心这些方法。

常见的ApplicationContext实现类

ClassPathXmlApplicationContext

如果配置文件放置在类路径下,则可以优先考虑使用ClassPathXmlApplicationContext实现类。

FileSystemXmlApplicationContext

如果配置文件放置在文件系统的路径下,则可以优先考虑使用FileSystemApplicationContext实现类。

AnnontationConfigApplicationContext

基于注解类的配置

BeanFactory和ApplicationContext的不同处

BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean才实例化目标Bean;而ApplicationContext则在初始化应用上下文就实例化所有单实例的Bean。因此,ApplicationContext的初始化时间会比BeanFactory稍长一些,不过稍后的调用则没有"第一次惩罚"的问题。

WebApplicationContext类体系结构

WebApplicationContext是专门为Web应用准备,它允许从相对于Web根目录的路径中装载配置文件完成初始化工作。从WebApplicationContext中可以获得ServletContext的引用,整个Web应用上下文对象将作为属性放置到ServletContext中,以便web应用环境可以访问Spring应用上下文。Spring专门为此提供了一个工具类WebApplicationContextUtils,通过该类的getWebApplicationContext(ServletContext sc)方法,可以从ServletContext中获取WebApplicationContext实例。
在非Web应用的环境中,Bean只用singleton和prototype两中作用域。WebApplicationContext为Bean添加了三个新的作用域:request、session和global session。
由于Web应用比一般的应用拥有更多的特性,因此WebApplicationContext扩展了ApplicationContext。WebApplicationContext定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文启动时,WebApplicationContext实例即以此为键放置在ServletContext的属性列表中,可以通过以下从Web容器中获取WebApplicationContext:

WebApplicationContext  wac = (WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

这就是WebApplicationContextUtils工具类getWebApplicationContext(ServletContext sc)方法的内部实现方式。这样Spring的Web应用上下文和Web容器的上下文应用就可以实现互访,二者实现了融合。
ConfigurableWebApplicationContext扩展了WebApplicationContext,它允许通过配置的方式实例化WebApplicationContext,同时定义了两个重要的方法:

  • setServletContext(ServletContext servletContext):为Spring设置Web应用上下文,以便二者整合;
  • setConfigLocations(String[] configLocatons):设置Spring配置文件地址,一般情况下,配置文件地址时相对Web根目录的地址,如/WEN-INF/**.xml等,但是用户也可以使用带资源类型前缀的地址。

WebApplicationContext初始化

WebApplicationContext的初始化方式和BeanFactory、ApplicationContext有所区别,因为WebApplicationContext需要ServletContext实例,也就说,它必须在拥有Web容器的前提下才能完成启动工作。可以在web.xml中配置自启动的Servlet或定义Web容器监听器(ServletContextListener),借助二者中的任何一个,就可以完成启动Spring Web应用上下文的工作。

Spring分别提供了用于启动WebApplicationContext的Servlet和Web容器监听器:

  • org.springframework.web.context.ContextLoaderServlet;
  • org.springframework.web.context.ContextLoadeerListener。
    二者的内部实现了启动WebApplicationContext实例的逻辑,只要根据Web容器的具体情况下选择二者之一,并在web.xml中完成配置即可。
<!--指定配置文件-->
<context-param>
    <param-name>
        contextConfigLocation
    </param-name>
    <param-value>
        /WEB-INF/**-dao.xml,/WEB-INF/**-service.xml
    </param-value>
</context-param>

<!--声明Web容器监听器--->
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

ContextLoaderListener通过Web容器上下文参数contextConfigLocation获取Spring配置文件的位置。用户可以指定多个配置文件,用逗号】空格或冒号分隔均可。
对于未带资源类型前置的配置文件,WebApplicationContext默认这些路径相对于Web的部署根路径。当然,也可以采用带资源类型前缀的路径配置。

如果在不支持容器监听器的低版本Web容器中,则可以采用ContextLoaderServlet完成相同的工作。

<context-param>
    <param-name>
        contextConfigLocation
    </param-name>
    <param-value>
         /WEB-INF/**-dao.xml,/WEB-INF/**-service.xml
    </param-value>
</context-param>

<!---声明自启动的Servlet-->
<servlet>
    <servlet-name>
        springContextLoaderServlet
    </servlet-name>
    <servlet-class>
        org.springframework.web.context.ContextLoaderServlet
    </servlet-class>

    <!--启动顺序-->
    <load-on-startup>1</load-on-startup>
</servlet>

用于WebApplicationConext需要使用日志功能,所以用户将Log4J的配置文件在类路径WEB-INF/classes下,这时Log4J引擎即可顺利启动,如果Log4J配置文件放置在其他位置,那么用户必须在wen.xml中指定Log4J配置文件的位置,Spring为启动Log4J引擎提供了两个类似与启动WebApplicationContext的实现类:Log4jConfigServlet和Log4jConfigListener,不管采用哪种方式,都必须保证能够在装载Spring配置文件前先装载log4J配置信息

<context-param>
    <param-name>
        contextConfigLocation
    </param-name>
    <param-value>
         /WEB-INF/**-dao.xml,/WEB-INF/**-service.xml
    </param-value>
</context-param>

<!--指定Log4J配置文件-->
<context-param>
    <param-name>
        log4jConfigLocation
    </param-name>
    <param-value>
        /WEB-INF/log4j.properties
    </param-value>
</context-param>

<!--装载Log4J配置文件的自启动Servlet-->
<servlet>
    <servlet-name>
        log4jConfigServlet
    </servlet-name>
    <servlet-class>
        org.springframework.web.utils.Log4jConfigServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet>
    <servlet-name>
        springContextLoaderServlet
    </servlet-name>
    <servlet-class>
        org.springframework.web.context.ContextLoaderServlet
    </servlet-class>

    <load-on-startup>2</load-on-startup>
</servlet>

注意上面将log4jConfigServlet的启动顺序号设置为1,而将springContextLoadeServlet的启动顺序号设置为2。这样,前者将启动,完成装载Log4J配置文件并初始化Log4J引擎的工作,紧接着后者再启动。如果使用Web监听器,则必须将Log4jConfigListener放置在ContextLoaderListener的前面。采用以上配置方式,Spring将自动使用XmlWebApplicationContext启动Spring容器,即通过XML文件为Spring容器提供Bean的配置信息。

如果使用标注@Configuration的Java类提供配置信息,则web.xml需要按以下方式配置:

<web-app>
    <!--通过指定context参数,让Spring使用AnnontationConfigWebApplicationContext而非XmlWebApplicationContext启动容器-->
    <context-param>
        <param-name>
            contextClass
        </param-nae>
        <param-value>
            org.springframework.web.context.AnnotationConfigApplicationContext
        </param-value>
    </context-param>

    <!--指定标注@Configuration的配置类,多个可以使用逗号或空格分隔-->
    <context-param>
        <param-name>
            contextConfigLocation
        </param-name>
        <param-value>
            org.aming.myproject.config.AppConfig
        </param-value>
    </context-param>

    <!--ContextLoaderListener监听器根据上面的配置使用AnnotationConfigWebApplicationContext根据contextConfigLoaction指定的配置类启动Spring容器-->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListner
        </listener-class>
    </listener>
</web-app>

ContextLoaderListener如果发现配置了contextClass上下文参数,就会使用参数所指定的WebApplicationContext实现类(AnnotationConfigWebApplicationContext)初始化容器,该实现类会根据contextConfigLocation上下文参数指定的@Configuration的配置类所提供的Spring配置信息初始化容器。

相关文章

这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原...
今天小编给大家分享的是一文解析spring中事务的传播机制,相...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓...