Spring大家族在Java技术生态体系中占有重要地位,其中Spring更是其中的佼佼者。它极大的简化了我们的代码开发量,提高我们的工作效率。
其中Spring两大特性中的IOC特性是至关重要的。今天来从底层看一看Spring的容器的初始化过程。算是我的学习笔记,也希望能对你有所帮助!
(如果有不懂IOC的小伙伴们可以去看一看我前面写的文章传送门在此)。
在开始之前,先思考几个问题。
- @Component,@Service,@Controller,@Repository@Bean等注解怎么实现的?
- @Autowired,@Resource 是怎么自动装配的?
- @ComponentScan 为什么就可以扫描注册Bean
对此我在其他博客看到一张图,感觉很生动形象。
IOC 容器 示意图
Spring IOC :
- Bean定义的定位,Bean 可以定义在XML中,或者一个注解,或者其他形式。这些都被用Resource来定位, 读取Resource获取BeanDefinition 注册到 Bean定义注册表中。
- 第一次向容器getBean操作会触发Bean的创建过程,实列化一个Bean时 ,根据BeanDefinition中类信息等实列化Bean.
- 将实列化的Bean放到单列Bean缓存内。
- 此后再次获取向容器getBean就会从缓存中获取。
OK,下面来看容器的初始化方法。
源码如下:
public void refresh() throws BeansException, IllegalStateException {
//同步代码块 。
synchronized (this.startupShutdownMonitor) {
// 准备刷新.
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();
}
}
1. prepareRefresh 准备刷新
- 设置启动时间,设计容器激活标志(active=true)
- 初始化 properties 资源
- 验证必须存在的properties(validateRequiredProperties)
- 初始earlyApplicationEnvents.用于收集已经产生的ApplicationEnvents.
2.obtainFreshBeanFactory 获取容器
- 调用子类的refeshBeanFactory(),SpringBoot中采用默认的实现,设置BeanFactory的SerializationId,设置refreshed标志为true。
- 获取BeanFactory
- XmlWebApplicationContext ,AnnotationConfigApplicationContext 会在这一步加载BeanDefinition