疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

spring ioc的源码简单介绍


 

 
 
          传统的java应用中,bean的生命周期很简单,关键字new初始化bean,然后嗲用,一旦这个bean不再使用则进入了垃圾回收阶段进行处理spring bean的生命周期:1)spring实例化bean开始
 
       2)spring为bean注入属性值和引用
       3)如果bean实现了BeanNameAware接口,spring将传递bean的id到setBeanName()方法中
       4)如果bean实现了BeanFactoryAware接口,spring将调用setBeanFactory方法并传递 bean factory本身进去。
        5)如果bean实现了ApplicationContextAware接口,spring将调用setApplicationContext方法并将上下文传递进去 
       6)如果bean实现了BeanPostProcessor接口,spring将调用他们的postProcessBeforeInitialization() 这个接口只是一个钩子,允许用户修改类的实例(Factory hook that allows for custom modification of new bean instances)
       7)如果bean实现了InitializingBean,spring将调用afterPropertiesSet()方法,类似的,如果bean在xml中有实现init-method,该方法也会被调用
        8)如果bean实现了BeanPostProcessor接口,spring将调用的postProcessAfterInitialization()方法
        9)这个时候,bean已经准备好了,可以被应用进行调用。他们一直存在应用的上下文中,直到该应用上下文被销毁掉。
       10)如果bean实现了DisposableBean接口,spring将调用destroy方法,同样,如果bean实现了destroy-method,该方法也会被调用。
 
       那spring是如何从xml中或者自动注解中解析管理bean的呢?在spring中beanfactory是ioc的核心,这个最重要的是就是根据名字或者类型返回一个bean的实例。提供最基础的依赖注入和bean的装配服务。但我们平时用的最多的就是ApplicationContext,这个也是从beanfactory扩展过来的。
实现类 :DefaultListableBeanFactory 
        /** Map of bean definition objects, keyed by bean name */
       private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
      看到这里,思路已经很明确了。bean工厂的初始化其实就是往这个map中填充东西。只要我们把xml中定义的bean都填充到这里,这个工厂就可以工作了。
       那么问题来了:那么从现在来看,我们需要什么才能把Map填充呢?也就是初始化bean工厂呢,或者说建立IOC容器。我首先列出来以下几步。
 

      1.需要一个File指向我们的XML文件(本文的配置文件都已XML为例,因为这是我们最熟悉的),专业点可以叫资源定位,简单点可以说我们需要一些工具来完成找到XML文件的所在位置。
        2.需要一个Reader来读取我们的XML文件,专业点叫DOM解析,简单点说,就是把XML文件的各种定义都给拿出来。
        3.需要将读出来的数据都设置到Map当中。
     这三部总结起来就是定位、解析、注册。我们首先按照这个思路来试一下。
代码:
 
 
public class TestDefaultListableBeanFactory {
  publicstaticvoid main(String[] args) {
      ClassPathResource classPathResource = new ClassPathResource("beans.xml");
       DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
     XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
      xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);
       System.out.println("numbers: " + defaultListableBeanFactory.getBeanDefinitionCount());
      ((Person)defaultListableBeanFactory.getBean("person")).work();
      }
     }
 
 

但没人希望通过这样的方式去获取一个bean,那么有没有更加简单的方式获取spring 的一个bean呢:
代码:
 
     public class TestApplicationContext {
      publicstaticvoid main(String[] args) {
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:beans.xml");
       System.out.println("numbers: " + applicationContext.getBeanDefinitionCount());
      ((Person)applicationContext.getBean("person")).work();
      }
     }
 

 
接下来我们看下FileSystemXmlApplicationContext这个类
 
最终构造函数调用:
 
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
 
 

 
        其中refresh()便是ioc容器的入口 refresh方法位于AbstractApplicationContext中,这是一个抽象类,初步实现了ApplicationContext的一般功能,refresh()方法列出了ioc容器的初始化的一些步骤,主要来看第二步,obtainFreshBeanFactory 这个方法步,它是用来告诉子类刷新内部的bean工厂
 
    /**
      * Tell the subclass to refresh the internal bean factory.
      * @return the fresh BeanFactory instance
      * @see #refreshBeanFactory()
      * @see #getBeanFactory()
      */
     protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
           refreshBeanFactory();
           ConfigurableListableBeanFactory beanFactory = getBeanFactory();
            if ( logger.isDebugEnabled()) {
                 logger.debug( "Bean factory for " + getDisplayName() + ": " + beanFactory);
           }
            return beanFactory;
     }
 
 
 

这里使用了模板模式,给以后要实现的子类提供了统一的模板,refreshBeanFactory,getBeanFactory都是抽象方法
先来看下refreshBeanFactory()具体实现
 
protected final void refreshBeanFactory() throws BeansException {
           if (hasBeanFactory()) {
                destroyBeans();
                closeBeanFactory();
           }
try {
                DefaultListableBeanFactory beanFactory = createBeanFactory();
                beanFactory.setSerializationId(getId());
                customizeBeanFactory(beanFactory);
                loadBeanDefinitions(beanFactory);               
synchronized (this.beanFactoryMonitor) {                     
this.beanFactory = beanFactory;
                }
           }catch (IOException ex) {                
throw new ApplicationContextException("I/O error parsing bean definition source for " +getDisplayName(), ex);
           }
     }
 
 
 

         方法加上了final关键字,也就是说此方法不可被重写,可以很清楚的看到,IOC容器的初始化就是在这个方法里发生的,第一步先是判断有无现有的工厂,有的话便会将其摧毁,否则,就会创建一个默认的bean工厂,也就是前面提到的DefaultListableBeanFactory,注意看loadBeanDefinitions(beanFactory);这里,当我们创建了一个默认的bean工厂以后,便是载入bean的定义,其FileSystemXmlApplicationContext的初始化方法中,已经为我们实现了beanfactory的实现类