spring ioc 源码解析

2013/13/3

传统的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()具体实现
 
 
复制代码
@Override
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的实现类
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值