博客主页:JavaProfessional
一个专注于Java的博主,致力于使用通俗易懂的语句讲解内容,期待您的关注!
文章目录
前言
看完本文你将获得:
- 掌握Spring IOC容器的启动顺序
如何学习Spring源码
我觉得学习源码最重要的就是抱着目的去看,因为优秀的项目是许多人智慧的结晶,代码量巨大,如果没有目的,那么很容易迷失方向。我们今天的第一节目的就是想要知道Spring的IOC容器是如何启动的,在源码中我们不可能面面俱到,所以有部分没有讲到,或者疑问,可以私信,我们日后再开一贴。
从Main开始
以下的main方法就是在新建一个IOC容器:
public class Main {
public static void main(String[] args) {
ApplicationContext springContext = new ClassPathXmlApplicationContext("spring-context.xml");
}
}
当然IOC容器的实现有很多,比如我们上面用到的ClassPathXmlApplicationContext,见名知意是从resource下获取xml文件新建IOC容器。还有很多实现如AnnotationConfigApplicationContext,见名知意是通过注解配置新建IOC容器。我们就以ClassPathXmlApplicationContext作为讲解的示例,其他的你可以自己尝试分析一下。
方法逐个讲解
ClassPathXmlApplicationContext的构造方法
作为唯一的一行代码,我们查看一下这个构造方法在做什么吧。
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
发现掉了另一个构造方法,并把传入的configLocation包装成了一个配置文件数组,然后第二三参数传入默认值。深入另一个构造方法。
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
一共有三步:
初始化父类
我们首先看一张ClassPathXmlApplicationContext的类图
就这样ClassPathXmlApplicationContext就一路初始化,从ClassPathXmlApplicationContext
->AbstractXmlApplicationContext
->AbstractRefreshableConfigApplicationContext
->AbstractRefreshableApplicationContext
->AbstractApplicationContext
。其他的暂时不是很重要,我们就看目前最顶级的AbstractApplicaitonContext中的resourcePatternResolver,其他成员变量都是默认值,这个成员变量在源码中有重要体现,因此我们单独说一下他是干什么的。
ResourcePatternResolver该接口用于解析带有*等通配符路径的资源文件,是ResourceLoader接口的拓展接口(不支持通配符)。PathMatchingResourcePatternResolver是此接口的独立实现。
具体使用可以查看这个文章
简单来说就是用来解析配置文件的,以下是在源码中的体现:
我们还在AbstractApplicationContext中看到了许多熟悉的概念:
这些我们在后面都会详细讲解,目前都是初始值(空)
设置配置文件的位置
就是保存配置文件的位置,我们看到在继承关系中,保存配置文件的类为AbstractRefreshableConfigApplicationContext,以Resource[]数组的形式保存,其子类都继承了该成员变量。
自动刷新
最后就来到我们的核心部分refresh,我们发现refresh是AbstractApplicationContext的代码。可见AbstractApplicationContext的重要。
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) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
this.startupShutdownMonitor
刷新容器和关闭容器的锁,开始刷新时需要抢到锁才能进行,如果没有抢到,需要等待关闭程序执行完毕才能开始。
prepareRefresh
// Prepare this context for refreshing.
prepareRefresh();
为容器刷新做准备,主要的工作是
- 记录启动时间
- 校验启动必要的配置是否齐全
- 将监听器列表初始化,并将
- 将事件列表初始化。
新建BeanFactory
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
主要功能有:
- 如果已经存在beanFactory则销毁后重新创建。
- 读入BeanDefinitions
我们一起来看看源码的实现吧
点入refreshBeanFactory的默认实现AbstractRefreshableApplicationContext
对新建的BeanFactory进行设置
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
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()));
}
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
总结
注意这里的refresh之前是指进入refresh方法之前,并非值prepareRefresh方法。