前面说到了spring使用配置文件来描述bean与bean之间的关系,并且由IOC容器来实例化这些bean,刚才的程序使用了ApplicationContext,其实它是建立在BeanFactory之上的, 也就是说BeanFactory是spring ioc容器底层的实现.它提供了ioc容器的基础功能;ApplicationContext在BeanFactory的基础上提供了更丰富的功能, 比如国际化, 框架事件.
在这里插一句,当你听到IOC容器的时候,或许你会觉得很陌生,那是因为你把它想复杂了,IOC容器也是普通的javaBean,是普通的java代码写的,只是它的功能有些特殊,它可以存放其他的对象,而且提供了访问途经(如:context.getBean("bean name");)就像List, map一样. 以后我们会经常使用IOC容器这个词,你完全可以理解为,就是BeanFactory,或者ApplicationContext.
BeanFactory只是一个接口,它最常用的实现类是XmlBeanFactory,现在来看如何用XmlBeanFactory来改写前面的主程序.
- package test;
- import model.Book;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.beans.factory.xml.XmlBeanFactory;
- import org.springframework.core.io.ClassPathResource;
- import org.springframework.core.io.Resource;
- public class TestXmlBeanFactory {
- public static void main(String[] args) {
- Resource res = new ClassPathResource("bean-test.xml");
- //Resource res = new FileSystemResource("C://project//spring//src//spring-test.xml");
- BeanFactory factory = new XmlBeanFactory(res);
- Book book = (Book)factory.getBean("myBook");
- System.out.println(book.toString());
- }
- }
用法基本和ApplicationContext一样,只是你会发现BeanFactory比ApplicationContext少了很多方法.BeanFactory需要一个Resource来加载配置文件.spring的Resource 表示一个与来源无关的资源, 它有两种典型的实现方式:ClassPathResource 从类路径加载资源, FileSystemResource从文件系统的某位置加载资源.
现在看一下建立在BeanFactory之上的ApplicationContext,它也有不同的实现方式,我们先前用到了ClassPathXmlApplicationContext来实例化一个ApplicationContext, 另外一种典型的方式是FileSystemXmlApplicationContext,它是从文件系统的某位置加载配置文件.因此,前面的ApplicationContext我们可以这样构造:ApplicationContext c = new FileSystemXmlApplicationContext("c://somepath//somefile");
ApplicationContext还有一个很有用的分支WebApplicationContext,是专门为web引用而设计的,这个在后面讨论spring mvc的时候再来讨论它.
现在思考一下:BeanFactory,顾名思义,就是创造Bean的工厂,它是怎么来创造bean的.来看一下一个bean的配置文件:
- <bean id="myBook" class="model.Book">
- <property name="id" value="000002" />
- <property name="name" value="Thinking in java" />
- <property name="author" value="Bruce Eckel" />
- <property name="price" value="2222" />
- </bean>
有类名,有属性名,有属性的value,聪明的你一定想到了, 用反射就可以把这个配置变成一个java 对象.不错,spring正是这样做的.如果你还没有了解反射, 建议你搜索以下,顺便了解一下Class这各类.如果你感兴趣, 也可以自己写一个BeanFactory试试看,其实不难; 如果你想看一看spring源码,你可以这样做:
在Eclipse/MyEclipse下,按住ctrl,在程序代码中鼠标点你想察看的类,如果你还没有给该类附加源代码,回出现如下一样的页面,比如我刚才想察看 WebApplicationContext:
点击attach source..., 点Exteral File..., 文件对话框中选择你的spring下载的解压包的dist/module-sources/spring-web-sources.jar.
这样就把所有的spring web相关的源码加入经来了.不要笑我罗索,我使用eclipse两年之后才会添加源码,因为没有人告诉我.
还可以打log的方式来看看BeanFactory初始化, 实例化,查找Bean的过程,这需要配置log4j. 在spring下载包下面的lib/log4j把该jar包拷贝到WEB-INF/lib,在src根目录建一个文件log4j.properties,内容如下:
- log4j.rootLogger=INFO, RC
- log4j.appender.RC=org.apache.log4j.ConsoleAppender
- log4j.appender.RC.threshold=debug
- log4j.appender.RC.layout=org.apache.log4j.PatternLayout
- log4j.appender.RC.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p :%m;%n
- log4j.appender.RC.immediateFlush=true
- log4j.logger.org.springframework=DEBUG
关于 log4j的配置不是本文的讨论范围,不过我还是稍微解释一下, 最上面6行配置了一个根 logger,消息会被输出到控制台,这句话 log4j.logger.org.springframework=DEBUG的意思是把 org.springframework包下面所有的日志输出的级别设为 DEBUG(最低级别),这样才可以输出 spring的 debug消息.
再重新运行程序,这时候在控制台你会看到 BeanFactory的所有的活动.