Spring IOC容器启动简介

BeanFactory和ApplicationContext都可以用来作为Bean工厂负责创建和管理Bean,相比之下ApplicationContext是BeanFactory的一个增强升级版,比如ApplicationContext提供了强大的事件机制,自动加载BeanPostProcessor(BPP)和BeanFactoryPostProcessor(BFPP),预创建Bean等,一般情况下都使用ApplicationContext来当作Bean工厂,除非某些对内存有严格要求的应用才会考虑使用BeanFactory,下面从源码入手基于ApplicationContext分析bean工厂的启动过程,ApplicationContext有FileSystemXmlApplicationContext、ClassPathXmlApplicationContext等实现,下面通过ClassPathXmlApplicationContext来进行分析。Spring的代码风格非常好,结构非常清晰便于阅读,基本上从方法名上就能猜出来这个方法的功能,从refresh这个方法就基本上能看出来容器在启动时做了哪些事情。这点非常值得我们学习,要写出高质量的代码多看看牛人的代码是非常有必要的。下面是容器启动的核心代码,反应了容器启动的核心步骤。

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
		throws BeansException {

	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
		refresh();
	}
}

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();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			finishRefresh();
		}

		catch (BeansException ex) {
			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}
	}
}
Sring容器在初始化的时候主要会做下面这些事情:

1、合并父容器的环境信息(Environment)

2、设置bean配置文件路径到容器中,如果路径中有占位符,替换占位符为真实路径

如下面的例子,路径中就包含了占位符, 占位符和路径对应关系存在System变量中,也可以使用环境变量中的value System.getenv()。

System.setProperty("config_folder", "spring/beans/test");
System.setProperty("config_file", "beans.xml");

BeanFactory context = new ClassPathXmlApplicationContext("${config_folder}/${config_file}");
System、环境变量等key-value对封装到org.springframework.core.env.PropertySource类,下面代码把这些key-value封装进PropertySource,org.springframework.core.env.StandardEnvironment类中的代码。

protected void customizePropertySources(MutablePropertySources propertySources) {
	propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
	propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
下面是提取占位符代码,在org.springframework.util.PropertyPlaceholderHelper类中
protected String parseStringValue(
		String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {

	StringBuilder buf = new StringBuilder(strVal);

	int startIndex = strVal.indexOf(this.placeholderPrefix);
	while (startIndex != -1) {
		int endIndex = findPlaceholderEndIndex(buf, startIndex);
		if (endIndex != -1) {
			String placeholder = buf.substring(startIndex + this.placeholderPrefix.length(), endIndex);
			...
		}
		else {
			startIndex = -1;
		}
	}

	return buf.toString();
}
提取出占位符之后从PropertySource中读取占位符对应的值,代码在org.springframework.core.env.PropertySourcesPropertyResolver类中。读取出来的值就是最终的Bean配置文件路径,容器根据这个路径加载配置文件

protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
	...
	if (this.propertySources != null) {
		for (PropertySource<?> propertySource : this.propertySources) {
			if (debugEnabled) {
				logger.debug(String.format("Searching for key '%s' in [%s]", key, propertySource.getName()));
			}
			Object value;
			if ((value = propertySource.getProperty(key)) != null) {
				...
				return this.conversionService.convert(value, targetValueType);
			}
		}
	}
	...
	return null;
}

3、准备刷新容器,校验坏境中的必须设置属性是否已经被设置

4、创建Bean工厂,ClassPathXmlApplicationContext不会加载和创建Bean,而是把这些工作代理给DefaultListableBeanFactory,这一步把这个bean工厂创建并且初始化

初始化Bean工厂要进行如下步骤

4.1、判断当前是否存在Bean工厂,如果已经存在,删除老Bean工厂注册的单例bean,关闭bean工厂,清除bean工厂的序列化id,清空beanFactory引用

4.2、创建bean工厂DefaultListableBeanFactory实例

4.3、设置bean工厂的序列化id,序列化id的默认格式是:ApplicationContext类权限名@ApplicationContext实例hashcode十六进制

序列化id是用来辅助Bean工厂序列化的,相关代码如下,因为DefaultListableBeanFactory是一个比较大的对象,里面包含了不少的字段,其中还有一些类型没有实现Serializable接口的字段,比如autowireCandidateResolver字段,所以无法直接对DefaultListableBeanFactory进行序列化,就算是把这种字段修饰成transient,序列化DefaultListableBeanFactory对象也是个比较好CPU的动作,所以经过如下处理,通过全局存储DefaultListableBeanFactory弱引用(不妨碍GC)和序列化id的映射关系,序列化时只需存储序列化id,反序列化时通过id查找DefaultListableBeanFactory实例。这样可以提高序列化效率。关于writeReplace和readResolve的用法可以直接问度娘。

public void setSerializationId(String serializationId) {
	if (serializationId != null) {
		serializableFactories.put(serializationId, new WeakReference<DefaultListableBeanFactory>(this));
	}
	else if (this.serializationId != null) {
		serializableFactories.remove(this.serializationId);
	}
	this.serializationId = serializationId;
}

protected Object writeReplace() throws ObjectStreamException {
	if (this.serializationId != null) {
		return new SerializedBeanFactoryReference(this.serializationId);
	}
	else {
		throw new NotSerializableException("DefaultListableBeanFactory has no serialization id");
	}
}

private static class SerializedBeanFactoryReference implements Serializable {

	private final String id;

	public SerializedBeanFactoryReference(String id) {
		this.id = id;
	}

	private Object readResolve() {
		Reference<?> ref = serializableFactories.get(this.id);
		if (ref == null) {
			throw new IllegalStateException(
					"Cannot deserialize BeanFactory with id " + this.id + ": no factory registered for this id");
		}
		Object result = ref.get();
		if (result == null) {
			throw new IllegalStateException(
					"Cannot deserialize BeanFactory with id " + this.id + ": factory has been garbage-collected");
		}
		return result;
	}
}
4.4、设置allowBeanDefinitionOverriding属性,是否允许覆盖bean定义,这个属性决定了配置文件中是否可以定义同名的bean,如果不允许的话容器会抛出BeanDefinitionStoreException异常,代码处理在DefaultListableBeanFactory的registerBeanDefinition方法。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
		throws BeanDefinitionStoreException {
		
		...
		
		Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			if (!this.allowBeanDefinitionOverriding) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			
		}
		
		...

}
4.5、设置allowCircularReferences属性,是否允许循环引用,默认是true允许,可以通过扩展ApplicationContext把它设置成false。
关于创建bean时的循环引用处理,在创建之前先判断bean的名称是否已经存在singletonsCurrentlyInCreation哈希表属性中,如果已经在这个哈希表中,说明这个bean正在创建,发生了循环引用在填充属性的时候又让回来了,这时候需要判断是否允许循环引用,如果允许的话提前暴露该bean的引用。在创建bean之前把bean的名称放到哈希表中,创建完成之后把它从哈希表中删除。

DefaultSingletonBeanRegistry

public boolean isSingletonCurrentlyInCreation(String beanName) {
	return this.singletonsCurrentlyInCreation.containsKey(beanName);
}

protected void beforeSingletonCreation(String beanName) {
	if (!this.inCreationCheckExclusions.containsKey(beanName) &&
			this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) {
		throw new BeanCurrentlyInCreationException(beanName);
	}
}
	
protected void afterSingletonCreation(String beanName) {
	if (!this.inCreationCheckExclusions.containsKey(beanName) &&
			!this.singletonsCurrentlyInCreation.remove(beanName)) {
		throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
	}
}

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(beanName, "'beanName' must not be null");
	synchronized (this.singletonObjects) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			...
			beforeSingletonCreation(beanName);
			...
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = new LinkedHashSet<Exception>();
			}
			try {
				...
			}
			catch (BeanCreationException ex) {
				...
			}
			finally {
				...
				afterSingletonCreation(beanName);
			}
			addSingleton(beanName, singletonObject);
		}
		...
	}
}
AbstractAutowireCapableBeanFactory类代码

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
	...
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		...
		addSingletonFactory(beanName, new ObjectFactory<Object>() {
			public Object getObject() throws BeansException {
				return getEarlyBeanReference(beanName, mbd, bean);
			}
		});
	}

	...
	
	if (earlySingletonExposure) {
		Object earlySingletonReference = getSingleton(beanName, false);//会调用上面的ObjectFactory.getObject()方法
		...
	}

	...

	return exposedObject;
}
4.6、加载bean定义,这个过程比较复杂,限于篇幅放到专门的文章分析。大致流程是:定位bean配置文件(ResourceLoader)-》解析Bean定义文件(BeanDefinitionDocumentReader)-》把bean定义解析成一个个的BeanDefinition对象,并且注册到容器中

5、给上一步创建的Bean工厂做一些准备工作,比如给Bean工厂注册类加载器PropertyEditor处理器,注册loadTimeWeaver、systemProperties、systemEnvironment等特殊bean

5.1、设置类加载器,如果没有设置,默认类加载器优先取当前线程上下文类加载器,如果未取到取ClassUtils类的类加载器,如果没取到取系统类加载器

public static ClassLoader getDefaultClassLoader() {
	ClassLoader cl = null;
	try {
		cl = Thread.currentThread().getContextClassLoader();
	}
	catch (Throwable ex) {
		// Cannot access thread context ClassLoader - falling back...
	}
	if (cl == null) {
		// No thread context class loader -> use class loader of this class.
		cl = ClassUtils.class.getClassLoader();
		if (cl == null) {
			// getClassLoader() returning null indicates the bootstrap ClassLoader
			try {
				cl = ClassLoader.getSystemClassLoader();
			}
			catch (Throwable ex) {
				// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
			}
		}
	}
	return cl;
}
5.2、设置EL表达式处理器StandardBeanExpressionResolver

5.3、增加默认的PropertyEditor注册器ResourceEditorRegistrar,关于PropertyEditor的详细分析参考Spring PropertyEditor分析

5.4、注册Aware接口处理器ApplicationContextAwareProcessor,这是一个BeanPostProcessor,它的职责是在bean创建完成之后触发该bean实现的所有Aware接口,比如ApplicationContextAware接口的setApplicationContext方法,EnvironmentAware接口的setEnvironment,xxxAware接口可以让应用代码持有容器中关键对象(比如ApplicationContext、Environment等)的引用,核心代码在ApplicationContextAwareProcessor的invokeAwareInterfaces方法:

private void invokeAwareInterfaces(Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
					new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}
}
5.5、注册几个自动装配相关的类和实例
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

这样的话容器就把bean工厂和ApplicationContext跟上面几个类型绑定了,在应用代码就可以通过类型自动装配把工厂实例和ApplicationContext实例设置到自定义bean的属性中。像下面的例子,beanFactory、resourceLoader、appContext、appEventPublisher这几个属性都会被自动设置,虽然没有在显示的在bean定义xml中注入它们。

public class AutowireByTypeBean {

	private Bean1 bean1;
	private BeanFactory beanFactory;
	private ResourceLoader resourceLoader;
	private ApplicationEventPublisher appEventPublisher;
	private ApplicationContext appContext;

	public BeanFactory getBeanFactory() {
		return beanFactory;
	}

	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}

	public ResourceLoader getResourceLoader() {
		return resourceLoader;
	}

	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}

	public ApplicationEventPublisher getAppEventPublisher() {
		return appEventPublisher;
	}

	public void setAppEventPublisher(ApplicationEventPublisher appEventPublisher) {
		this.appEventPublisher = appEventPublisher;
	}

	public ApplicationContext getAppContext() {
		return appContext;
	}

	public void setAppContext(ApplicationContext appContext) {
		this.appContext = appContext;
	}

	public Bean1 getBean1() {
		return bean1;
	}

	public void setBean1(Bean1 bean1) {
		this.bean1 = bean1;
	}

}
<bean id="autowireBean" class="spring.beans.autowire.AutowireByTypeBean"
	autowire="byType"></bean>
<bean id="bean1111" class="spring.beans.autowire.Bean1">
	<property name="id" value="1"></property>
</bean>

5.6、处理LTW(LoadTimeWeaver) aware接口,增加一个bean后处理器LoadTimeWeaverAwareProcessor,让所有实现了LoadTimeWeaverAware接口的bean都可以持有LTW实例,代码在prepareBeanFactory方法

if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
	beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
	// Set a temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
关于LTW的详细分析参考 Spring AspectJ LTW

5.7、注册坏境bean

  • 检查当前Context是否定义了id为environment的bean,如果没有定义,把StandardEnvironment注册到容器中,id为environment,这个bean包含了所有系统变量和环境变量
  • 检查当前Context是否定义了id为systemProperties,如果没有定义,把系统变量Map注册到容器中,id为systemProperties
  • 检查当前Context是否定义了id为systemEnvironment,如果没有定义,把环境变量Map注册到容器中,id为systemEnvironment

6、激活所有BeanFactoryPostProcessor接口,包括容器内置的和应用自定义的,所有的BFPP实现了PriorityOrdered接口归类并排序,实现了Ordered接口的归类并排序,未实现排序接口的归类,先按顺序执行实现了PriorityOrdered接口的BFPP,然后按顺序执行实现了Ordered接口的BFPP,最后执行未实现排序接口的BFPP。其中还有个特殊的BFPP BeanDefinitionRegistryPostProcessor接口,它是用来扩展一些特殊的Bean定义,比如有个实现ConfigurationClassPostProcessor,它是用来处理@Configuration注解描述的bean定义,在bean定义文件中定义了<context:annotation-config />标签之后,容器会自动注册一个ConfigurationClassPostProcessor来对指定包中包含@Configuration注解的类进行解析。

7、把所有实现BeanPostProcessor接口的bean注册到工厂中,为后面激活这些BPP做准备,所有实现了PriorityOrdered接口的归类并排序,实现了Ordered接口的归类并排序,未实现排序接口的归类,还有一个BPP扩展MergedBeanDefinitionPostProcessor接口,实现了这个接口的bean也单独归类,这个接口在容器中有一些实现:AutowiredAnnotationBeanPostProcessor、InitDestroyAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor、ApplicationListenerDetector,它们分别处理@Autowired、@PostConstructed和@PreDestroy注解、@Required注解、检测ApplicationListener接口。容器会额外注册一个ApplicationListenerDetector BPP用来检测所有实现了ApplicationListener接口的bean并把它们注册到Application时间广播器中,当容器事件被激活时事件会传递到这些实现了ApplicationListener接口的bean

8、处理国际化资源bean,检查是否定义了名为messageSource的bean,如果已经注册,用这个bean来处理国际化资源,这个bean必须是实现了MessageSource接口的bean,Spring中有个默认的国际化资源实现ResourceBundleMessageSource,它是基于JDK中的ResourceBundle实现的,用法如下:

<bean id="messageSource"
	class="org.springframework.context.support.ResourceBundleMessageSource">
	<property name="basenames">
		<list>
			<value>spring.beans.messagesource.message</value>
		</list>
	</property>
</bean>

ApplicationContext context = new ClassPathXmlApplicationContext(
		"spring/beans/messagesource/messagesource.xml");
String name = context.getMessage("cyy.name", null, Locale.ENGLISH);
在spring/beans/messagesource目录下需要增加message_zh.properties、message_en.properties等资源文件

9、初始化容器事件广播器

检查是否定义了applicationEventMulticaster名称的bean,如果没有创建SimpleApplicationEventMulticaster实例记录到容器,用来广播容器事件到各个队容器事件感兴趣的监听者

protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
		this.applicationEventMulticaster =
				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
	}
	else {
		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
	}
}

10、把应用层注册的容器事件监听器添加到容器中

和ApplicationListenerDetector作用重复,但是ApplicationListenerDetector能够检查到实现了ApplicationListener接口的内嵌Bean,而这一步只能检查到实现了ApplicationListener接口的顶层bean

protected void registerListeners() {
	// Register statically specified listeners first.
	for (ApplicationListener<?> listener : getApplicationListeners()) {
		getApplicationEventMulticaster().addApplicationListener(listener);
	}
	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let post-processors apply to them!
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	for (String lisName : listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(lisName);
	}
}


11、结束Bean工厂的初始化,清理一些变量并且预加载创建单例Bean

  • 检查是否定义了conversionService名称的bean,如果是把这个bean当做容器的类型转换器
  • 提前初始化LTW bean,把类转换器(ClassFileTransformer)提前注册到类加载器中,为切面编织做准备
  • 清空临时类加载器
  • 冻结所有bean定义,让它们不能再被修改
  • 提前初始化单例bean,检查所有bean,如果bean有父bean,把父bean和子bean的属性信息合并,检查bean是否是非抽象、单例、没有设置lazy-init,如果是初始化bean。这个步骤比较复杂,需要一篇专门的文章分析

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// Initialize conversion service for this context.
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}

	// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}

	// Stop using the temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(null);

	// Allow for caching all bean definition metadata, not expecting further changes.
	beanFactory.freezeConfiguration();

	// Instantiate all remaining (non-lazy-init) singletons.
	beanFactory.preInstantiateSingletons();
}

12、结束容器刷新

  • 注册lifecycle处理器lifecycleProcessor到容器,检查是否定义了lifecycleProcessor名称的bean,如果没有创建一个DefaultLifecycleProcessor实例,并且注册到容器中,用它来处理容器的lifecycle
  • 传播容器的refresh事件到lifecycleProcessor
  • 广播容器刷新事件,所有实现了ApplicationListener事件的bean都可以监听到该事件

protected void finishRefresh() {
	// Initialize lifecycle processor for this context.
	initLifecycleProcessor();

	// Propagate refresh to lifecycle processor first.
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	publishEvent(new ContextRefreshedEvent(this));

	// Participate in LiveBeansView MBean, if active.
	LiveBeansView.registerApplicationContext(this);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值