BeanFactory简单介绍
一、BeanFactory BeanFactory,以Factory结尾,表示它是一个工厂类(接口),它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,...
一、 BeanFactory
BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
它为其他具体的IOC容器提供了最基本的规范,例如DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext 等具体的容器都是实现了BeanFactory,再在其基础之上附加了其他的功能。
原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。ApplicationContext接口,它由BeanFactory接口派生而来。现在一般使用ApplicationnContext,其不但包含了BeanFactory的作用,同时还进行更多的扩展。
BeanFactory实际上是实例化,配置和管理众多bean的容器。 这些bean通常会彼此合作,因而它们之间会产生依赖。 BeanFactory使用的配置数据可以反映这些依赖关系中,一个BeanFactory可以用接口org.springframework.beans.factory.BeanFactory表示, 这个接口有多个实现。 最常使用的的简单的BeanFactory实现是org.springframework.beans.factory.xml.XmlBeanFactory。
几乎所有被BeanFactory管理的用户代码都不需要知道BeanFactory, 但是BeanFactory还是以某种方式实例化。如我们执行了以下代码:
InputStream is = new FileInputStream("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
//或者
ClassPathResource res = new ClassPathResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
//或者
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
// of course, an ApplicationContext is just a BeanFactory
BeanFactory factory = (BeanFactory) appContext;
很多情况下,用户代码不需要实例化BeanFactory, 因为Spring框架代码会做这件事。
二、生命周期接口
Spring提供了一些标志接口,用来改变BeanFactory中的bean的行为。 它们包括InitializingBean和DisposableBean。 实现这些接口将会导致BeanFactory调用前一个接口的afterPropertiesSet()方法, 调用后一个接口destroy()方法,从而使得bean可以在初始化和析构后做一些特定的动作。
1、 InitializingBean / init-method
实现org.springframework.beans.factory.InitializingBean 接口允许一个bean在它的所有必须的属性被BeanFactory设置后, 来执行初始化的工作。InitializingBean接口仅仅制定了一个方法:
void afterPropertiesSet() throws Exception;
注意:通常InitializingBean接口的使用是能够避免的(而且不鼓励,因为没有必要把代码同Spring耦合起来)。Bean的定义支持指定一个普通的初始化方法。在使用XmlBeanFactory的情况下,可以通过指定init-method属性来完成。
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
public void init() {
// do some initialization work
}
}
2、DisposableBean / destroy-method
实现org.springframework.beans.factory.DisposableBean接口允许一个bean, 可以在包含它的BeanFactory销毁的时候得到一个回调。DisposableBean也只指定了一个方法:
void destroy() throws Exception;
注意:通常DisposableBean接口的使用能够避免的(而且是不鼓励的,因为它不必要地将代码耦合于Spring)。 Bean的定义支持指定一个普通的析构方法。在使用XmlBeanFactory使用的情况下,它是通过 destroy-method属性完成。 举例来说,下面的定义:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="destroy"/>
public class ExampleBean {
public void cleanup() {
// do some destruction work (like closing connection)
}
}
三、其他类介绍
1. BeanFactoryAware
对于实现了org.springframework.beans.factory.BeanFactoryAware接口的类, 当它被BeanFactory创建后,它会拥有一个指向创建它的BeanFactory的引用。这允许bean可以以编程的方式操控创建它们的BeanFactory,但是一般来说它应该避免使用,因为它使代码与Spring耦合在一起。
2、获得一个FactoryBean而不是它生成的bean
有些时候我们需要向BeanFactory请求实际的FactoryBean实例本身, 而不是它生产出来的bean。在调用BeanFactory (包括ApplicationContext)的getBean方法的时候, 在传入的参数bean id前面加一个“&”符号,就可以做到这一点。所以,对于一个id为getBean的FactoryBean, 在BeanFactory上调用getBean("myBean")将会返回FactoryBean的产品,而调用getBean("&myBean")将会返回这个FactoryBean实例本身。
3、介绍ApplicationContext
Context包的基础是位于org.springframework.context包中的ApplicationContext接口。它是由BeanFactory接口集成而来,提供BeanFactory所有的功能。为了以一种更向面向框架的方式工作,context包使用分层和有继承关系的上下文类,包括:
-
MessageSource, 提供对i18n消息的访问
-
资源访问, 比如URL和文件
-
事件传递给实现了ApplicationListener接口的bean
-
载入多个(有继承关系)上下文类,使得每一个上下文类都专注于一个特定的层次,比如应用的web层
因为ApplicationContext包括了BeanFactory所有的功能,所以通常建议先于BeanFactory使用,除了有限的一些场合比如在一个Applet中,内存的消耗是关键的,每kb字节都很重要。接下来的章节将叙述ApplicationContext在BeanFactory的基本能力上增建的功能。
(1)使用MessageSource
ApplicationContext接口继承MessageSource接口,所以提供了messaging功能(i18n或者国际化)同NestingMessageSource一起使用,就能够处理分级的信息,这些是Spring提供的处理信息的基本接口。让我们很快浏览一下这里定义的方法:
-
String getMessage (String code, Object[] args, String default, Locale loc):这个方法是从MessageSource取得信息的基本方法。如果对于指定的locale没有找到信息,则使用默认的信息。传入的参数args被用来代替信息中的占位符,这个是通过Java标准类库的MessageFormat实现的。
-
String getMessage (String code, Object[] args, Locale loc):本质上和上一个方法是一样的,除了一点区别:没有默认值可以指定;如果信息找不到,就会抛出一个NoSuchMessageException。
-
String getMessage(MessageSourceResolvable resolvable, Locale locale):上面两个方法使用的所有属性都是封装到一个叫做MessageSourceResolvable的类中,你可以通过这个方法直接使用它。
当ApplicationContext被加载的时候,它会自动查找在context中定义的MessageSource bean。这个bean必须叫做messageSource。
(2)事件传递
ApplicationContext中的事件处理是通过ApplicationEvent类和ApplicationListener接口来提供的。如果上下文中部署了一个实现了ApplicationListener接口的bean,每次一个ApplicationEvent发布到ApplicationContext时,那个bean就会被通知。
(3)在Spring中使用资源
很多应用程序都需要访问资源。资源可以包括文件,以及象web页面或NNTP newsfeeds的东西。Spring提供了一个清晰透明的方案,以一种协议无关的方式访问资源。ApplicationContext接口包含一个方法(getResource(String))负责这项工作。
(4)在ApplicationContext中定制行为
BeanFactory已经提供了许多机制来控制部署在其中的bean的生命周期(比如象InitializingBean或DisposableBean的标志接口,它们的配置效果和XmlBeanFactory配置中的init-method和destroy-method属性以及bean post-processor是相同的。在ApplicationContext中,这些也同样可以工作,但同时也增加了一些用于定制bean和容器行为的机制。
常用的有ApplicationContextAware标记接口
所有BeanFactory中可用的标志接口这里也可以使用。ApplicationContext又增加了一个bean可以实现的标志接口:org.springframework.context.ApplicationContextAware。如果一个bean实现了这个接口并且被部署到了context中,当这个bean创建的时候,将使用这个接口的setApplicationContext()方法回调这个bean,为这个bean提供一个指向当前上下文的引用,这个引用将被存储起来以便bean以后与上下文发生交互。
从一个web应用创建ApplicationContext
与BeanFactory总是以编程的方式创建相反,ApplicationContext可以通过使用比如ContextLoader声明式地被创建。当然你也可以用ApplicationContext的任一种实现来以编程的方式创建它。首先,我们来看看ContextLoader以及它的实现。
ContextLoader有两个实现:ContextLoaderListener和ContextLoaderServlet。它们两个有着同样的功能,除了listener不能在Servlet 2.2兼容的容器中使用。自从Servelt 2.4规范,listener被要求在web应用启动后初始化。很多2.3兼容的容器已经实现了这个特性。使用哪一个取决于你自己,但是如果所有的条件都一样,你大概会更喜欢ContextLoaderListener;关于兼容方面的更多信息可以参照ContextLoaderServlet的JavaDoc。
你可以象下面这样用ContextLoaderListener注册一个ApplicationContext:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- OR USE THE CONTEXTLOADERSERVLET INSTEAD OF THE LISTENER
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
-->
这个listener需要检查contextConfigLocation参数。如果不存在的话,它将默认使用/WEB-INF/applicationContext.xml。如果它存在,它就会用预先定义的分隔符(逗号,分号和空格)分开分割字符串,并将这些值作为应用上下文将要搜索的位置。ContextLoaderServlet可以用来替换ContextLoaderListener。这个servlet像listener那样使用contextConfigLocation参数。
二、DefaultListableBeanFactory,XmlBeanFactory
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
从上面可以看出XmlBeanFactory继承了DefaultListableBeanFactory,DefaultListableBeanFactory是Spring注册加载bean的默认实现,它是整个bean加载的核心部分。
XmlBeanFactory与它的不同点就是XmlBeanFactory使用了自定义的XML读取器XmlBeanDefinitionReader,实现了自己的BeanDefinitionReader读取。 XmlBeanFactory加载bean的关键就在于XmlBeanDefinitionReader。
更多推荐
所有评论(0)