Spring Bean加载过程(一)

本文详细解析了Spring框架中IoC容器如何加载Bean定义资源文件的过程,包括ApplicationContext接口的不同实现方式以及Bean定义资源文件的具体加载步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自:
http://blog.youkuaiyun.com/chjttony/article/details/6248682
http://blog.youkuaiyun.com/chjttony/article/details/6263347
http://blog.youkuaiyun.com/chjttony/article/details/6278627


  Spring Bean的加载依赖于BeanFactory,但实际使用时不会直接使用BeanFactory,而是采用ApplicationContext这个在BeanFactory基础上提供了扩展的接口:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, 
    HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    

  ApplicationContext接口具体的实现类常用的有:FileSystemXmlApplicationContet (从文件系统中读入Bean定义资源文件)、ClassPathXmlApplicationContext(从Classpath类路径中读入Bean定义资源文件)和XmlWebApplicationContext(从Web容器如Tomcat等中读入Bean定义资源文件)等。

  以FileSystemXmlApplicationContext为例,通过分析FileSystemXmlApplicationContext及其父类的源码来分析IoC容器定位Bean定义资源文件的实现过程:

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {

	public FileSystemXmlApplicationContext() {
	}

	public FileSystemXmlApplicationContext(ApplicationContext parent) {
		super(parent);
	}
    //configLocation是Bean定义资源文件路径
	public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}

	public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
		this(configLocations, true, null);
	}

	public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
		this(configLocations, true, parent);
	}

	public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
		this(configLocations, refresh, null);
	}

	public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {
		super(parent);
        //调用父类AbstractRefreshableConfigApplicationContext的方法,
        //设置Bean定义的资源文件,完成IoC容器Bean定义资源的定位
		setConfigLocations(configLocations);
		if (refresh) {
            //调用父类AbstractApplicationContext的refresh()
            //函数启动载入Bean定义的过程,是Ioc容器载入Bean定义的入口
			refresh();
		}
	}

	@Override
	protected Resource getResourceByPath(String path) {
		if (path != null && path.startsWith("/")) {
			path = path.substring(1);
		}
		return new FileSystemResource(path);
	}
}

  通过代码可以知道,在创建FileSystemXmlApplicationContext容器时,首先,调用父类容器的构造方法super(parent)方法为容器设置好Bean资源加载器。然后,再调用setConfigLocations(configLocations)方法设置Bean定义资源文件的定位路径。

  Spring IoC容器对Bean定义资源的载入是从refresh()函数开始的,FileSystemXmlApplicationContext通过调用其父类AbstractApplicationContextrefresh()函数开始整个IoC容器对Bean定义的载入过程。AbstractApplicationContext#refresh()载入Bean定义过程:

public void refresh() throws BeansException, IllegalStateException {  
        synchronized (this.startupShutdownMonitor) {  
            prepareRefresh();  
            
            //创建bean工厂 
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
            
            //为BeanFactory配置容器特性,例如类加载器、事件处理器等  
            prepareBeanFactory(beanFactory);  
            try {  
                //为容器的某些子类指定特殊的BeanPost事件处理器
                postProcessBeanFactory(beanFactory);  
                
                //调用所有注册的BeanFactoryPostProcessor的Bean  
                invokeBeanFactoryPostProcessors(beanFactory);  
                
                //为BeanFactory注册BeanPost事件处理器.  
                //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件  
                registerBeanPostProcessors(beanFactory);  
                
                //初始化信息源,和国际化相关.  
                initMessageSource();  
                
                //初始化容器事件传播器.  
                initApplicationEventMulticaster();  
                
                //调用子类的某些特殊Bean初始化方法  
                onRefresh();  
                
                //为事件传播器注册事件监听器.  
                registerListeners();  
                
                //初始化所有剩余的单态Bean.  
                finishBeanFactoryInitialization(beanFactory);  
                
                //初始化容器的生命周期事件处理器,并发布容器的生命周期事件  
                finishRefresh();  
            }  
            catch (BeansException ex) {  
                //销毁以创建的单态Bean  
                destroyBeans();  
                //取消refresh操作,重置容器的同步标识.  
                cancelRefresh(ex);  
                throw ex;  
            }  
        }  
    }  

  refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以refresh()obtainFreshBeanFactory()是载入过程的开始:

    //AbstractApplicationContext.java
	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	    //这里是关键的 refreshBeanFactory 方法
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

  AbstractApplicationContextobtainFreshBeanFactory()方法调用refreshBeanFactory()方法,启动容器载入Bean定义资源文件的过程。AbstractApplicationContext类中只抽象定义了refreshBeanFactory()方法,容器真正调用的是其子类AbstractRefreshableApplicationContext#refreshBeanFactory(),方法的源码如下:

protected final void refreshBeanFactory() throws BeansException {  
        if (hasBeanFactory()) {
            destroyBeans();  
            closeBeanFactory();  
        }  
        try {  
            //创建IoC容器  
            DefaultListableBeanFactory beanFactory = createBeanFactory();  
            beanFactory.setSerializationId(getId());  
            //对IoC容器进行定制化,如设置启动参数,开启注解的自动装配等  
            customizeBeanFactory(beanFactory);  
            //调用载入Bean定义的方法,具体的实现调用子类容器
            loadBeanDefinitions(beanFactory);  
            synchronized (this.beanFactoryMonitor) {  
                this.beanFactory = beanFactory;  
            }  
        }  
        catch (IOException ex) {  
            throw new ApplicationContextException("I/O error parsing bean definition source for " +
                getDisplayName(), ex);  
        }  
    }  

  refreshBeanFactory()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入。
  createBeanFactory()是创建了DefaultListableBeanFactory工厂,载入BeanDefinition的方法loadBeanDefinitions只是AbstractRefreshableApplicationContext类中的抽象方法。
  AbstractRefreshableApplicationContext的子类有XmlWebApplicationContextAnnotationConfigWebApplicationContext。看类名就大概知道分别是解析哪种类型的配置。
  解析好的BeanDefinition,由 BeanDefinitionReaderUtils.registerBeanDefinition() 注册到DefaultListableBeanFactory中的beanDefinitionMap

/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = 
    new ConcurrentHashMap<String, BeanDefinition>(256); 

  注意上里的BeanDefinition只是解析后的类Bean定义的相关数据,并没进行依赖注入,依赖注入在以下两种情况发生:

(1)用户第一次通过getBean方法向IoC容索要Bean时,IoC容器触发依赖注入。
(2)当用户在Bean定义资源中为<Bean>元素配置了lazy-init属性,即让容器在解析注册Bean定义时进行预实例化,触发依赖注入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值