spring ioc的源码简单介绍
2013/13/3
传统的java应用中,bean的生命周期很简单,关键字new初始化bean,然后嗲用,一旦这个bean不再使用则进入了垃圾回收阶段进行处理
spring bean的生命周期:
- spring实例化bean开始
- spring为bean注入属性值和引用
- 如果bean实现了BeanNameAware接口,spring将传递bean的id到setBeanName()方法中
- 如果bean实现了BeanFactoryAware接口,spring将调用setBeanFactory方法并传递 bean factory本身进去。
- 如果bean实现了ApplicationContextAware接口,spring将调用setApplicationContext方法并将上下文传递进去
- 如果bean实现了BeanPostProcessor接口,spring将调用他们的postProcessBeforeInitialization() 这个接口只是一个钩子,允许用户修改类的实例(Factory hook that allows for custom modification of new bean instances)
- 如果bean实现了InitializingBean,spring将调用afterPropertiesSet()方法,类似的,如果bean在xml中有实现init-method,该方法也会被调用
- 如果bean实现了BeanPostProcessor接口,spring将调用的postProcessAfterInitialization()方法
- 这个时候,bean已经准备好了,可以被应用进行调用。他们一直存在应用的上下文中,直到该应用上下文被销毁掉。
- 如果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的实现类