Spring 提供的最基本的Ioc容器接口是BeanFactory, 通过BeanFactory可以获取bean对象的实例, 但BeanFactory 是怎么从配置文件里读取的bean对象的信息呢?
下面的代码是BeanFactory去获取spring.xml配置的bean的实例:
package com.younchen.test; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import com.younchen.model.Person; public class GetBeanTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub //Spring IOC 容器之一BeanFactory //获取资源文件 Resource resource=new ClassPathResource("spring.xml"); //bean工厂 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); //reader XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFactory); //reader去读取资源文件 reader.loadBeanDefinitions(resource); //获取bean对象 Person person=(Person) beanFactory.getBean("person"); person.setName("youn"); System.out.println(person.getName()); } }
看一下Resource变量,Spring里提供了Resource接口,它是抽象资源接口,classpath中的bean.xml ,spring.xml 都可以描述为抽象资源。
Resource 接口有以下的实例:
UrlResource:访问网络资源的实现类。
ClassPathResource:访问类加载路径里资源的实现类。
FileSystemResource:访问文件系统里资源的实现类。
ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类:
InputStreamResource:访问输入流资源的实现类。
ByteArrayResource:访问字节数组资源的实现类。
上面的列子中Resource获取的实例是ClassPathResource,该类用于读取类加载路径(classpath)中的spring.xml,接下来创建BeanFactory 这个时候新创建的beanFactory还不能直接使用,因为beanFactory没有获取到配置文件信息, 读取配置文件的工作是由Resource完成,而解析的时候由BeanDefinitionReader来完成。 实例化beanDefinitionReader时需要将beanFactory传递进去,目的是将解析后的bean信息传给beanFactory。 接下来beanDefinitionReader去解析Resource读取到的配置文件,这一步完成以后beanFactory就可以工作了,简单描述步骤就是:
1.创建Ioc容器抽象资源
2.创建一个BeanFactory
3.将配置文件解析器配置给BeanFactory
4.解析器去读取配置文件
5.BeanFacotory获取指定的bean对象实例
下面简单介绍一下ApplicationContext 即上下文, 上面的例子可以看出BeanFactory并没有资源定义的能力,
他需要解析器去解析之后配置给BeanFactory, 而ApplicationContext却拥有对资源的定义能力,更确切的说 Application包含了BeanFactory ,先看下代码:
package com.younchen.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.younchen.model.PersonModel; import com.younchen.util.SpringUtil; public class ApplicationContextTest { public static void main(String[] args){ ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml"); PersonModel personModel =(PersonModel) context.getBean("personModel"); personModel.getPerson().setName("黑猫"); personModel.showPersonName(); }
上面的代码是上下文去获取配置文件定义的bean对象的实例,可以通过debug模式跟进去看Application的创建过程,
实例化的过程他会调用refresh方法:
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //...........省略 } }
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()这一句代码创建并配置BeanFactory,
继续追踪会到:
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); // ............省略 } } catch (IOException ex) { //..............省略 } }
try语句中第一行代码 createBeanFactory()方法是创建BeanFactory的一个实例, 再往下走到loadBeanDefinitions(beanFactory)方法 ,loadBeanDefinitions应该比较熟悉了吧? 用来解析配置文件的,代码如下:
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
这个方法中 首先实例化了BeanDefinitionReader ,之后通过loadBeanDefinitions 方法读取配置文件 代码如下:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
到此就完成了 ApplicationContext 内置的BeanFactory的创建,及将配置文件配置给BeanFactory。
当ApplicationContext执行getBean()方法时 实际上执行的是BeanFactory的getBean方法。
以上是Spring上下文获取配置文件中bean对象的过程,欢迎指正^^