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