Spring IOC
Spring IOC
IOC 容器是 Spring 的一大特性,在开发过程中也经常会用到容器提供的一些功能,所以便对容器相关的源码进行了阅读了解,为了更好的梳理 Spring IOC 容器相关逻辑,主要以经典的 ClassPathXmlApplicationContext
容器做分析,常用的注解类容器主要原理与之相似,可参考阅读。
tips: 阅读前,你需要对 Spring 有一些了解。
1 容器初始化
首先写一个 xml 配置文件,Cat
和 Dog
为容器中的两个bean。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd ">
<bean id="cat" class="com.blacklad.test.spring.Cat" >
</bean>
<bean id="dog" class="com.blacklad.test.spring.Dog" >
</bean>
</beans>
通过 xml 创建一个 ClassPathXmlApplicationContext
容器。
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-ioc.xml");
Cat cat = ctx.getBean("cat", Cat.class);
Dog dog = ctx.getBean("dog", Dog.class);
}
2 启动流程
在创建ClassPathXmlApplicationContext
对象时,Spring 就对容器进行了初始化。并将 xml 文件的路径保存下来,然后调用 refresh
方法。
// org.springframework.context.support.ClassPathXmlApplicationContext
public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
refresh
方法时整个 Spring 容器启动的核心,其代码也是写在了抽象类AbstractApplicationContext
中,所有实现这个类的容器都会调用这个方法刷新(初始化),方法中每一步都是通过调用一个函数实现,其中一部分是抽象方法,交给子类实现。(用到了模板方法的设计模式),整个步骤清晰明了。
// org.springframework.context.support.AbstractApplicationContext#refresh
@Override
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();
}
}
}
3 refresh
方法内首先会加同步锁,保证线程安全。
3.1 prepareRefresh
准备刷新阶段,设置启动时间和刷新开始标志。
3.2 obtainFreshBeanFactory
通过子类实现refreshBeanFactory
方法刷新beanFactory。
// org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory
/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
refreshBeanFactory
中首先会 create
一个 beanFactory
-> DefaultListableBeanFactory
,然后对其进行初始化,并通过 loadBeanDefinitions()
加载所有的bean配置作为beanDefinition对象放入beanDefinitionMap中。
// org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
3.3 prepareBeanFactory
对 BeanFactory 做一些预备的配置,如 ClassLoader
、factory
相关的 BeanPostProcessor
和一些默认的bean。
3.4 postProcessBeanFactory
在工厂初始化后,对 BeanFactory
做一些修改。
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for registering special
* BeanPostProcessors etc in certain ApplicationContext implementations.
* @param beanFactory the bean factory used by the application context
*/
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
3.5 invokeBeanFactoryPostProcessors
调用所有的 BeanFactoryPostProcessors
。
// org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
/**
* Instantiate and invoke all registered BeanFactoryPostProcessor beans,
* respecting explicit order if given.
* <p>Must be called before singleton instantiation.
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
invokeBeanFactoryPostProcessors
内会按照优先级依次处理。
首先会优先处理实现了
BeanFactoryPostProcessor
的子接口BeanDefinitionRegistryPostProcessor
的类中的方法postProcessBeanDefinitionRegistry()
。然后依调用实现了
BeanFactoryPostProcessor
接口的类中的postProcessBeanFactory
方法。
3.6 registerBeanPostProcessors
按照优先级注册所有实现了 BeanPostProcessor
的类。
/**
* Instantiate and register all BeanPostProcessor beans,
* respecting explicit order if given.
* <p>Must be called before any instantiation of application beans.
*/
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
3.7 initMessageSource
初始化国际化相关配置。
3.8 initApplicationEventMulticaster
初始化事件广播器,会创建一个SimpleApplicationEventMulticaster
对象放入beanFactory容器中。
3.9 onRefresh
模板方法,供子类实现去做一些额外的刷新功能,如初始化一些特殊的 beans
。
/**
* Template method which can be overridden to add context-specific refresh work.
* Called on initialization of special beans, before instantiation of singletons.
* <p>This implementation is empty.
* @throws BeansException in case of errors
* @see #refresh()
*/
protected void onRefresh() throws BeansException {
// For subclasses: do nothing by default.
}
3.10 registerListeners
将事件监听器(即实现了 ApplicationListener
接口的类)注册到事件广播器中。
3.11 finishBeanFactoryInitialization
完成对 beanfactory
的初始化, 同时对BeanFactory中的 singleton bean
进行初始化。
/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
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));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 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();
}
preInstantiateSingletons
中会遍历所有的 beanDefinition
信息,找到 非抽象、单例且非懒加载 的类通过调用 getBean
方法进行初始化 bean
。
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
3.12 finishRefresh
完成 context
的刷新,清理资源,初始化生命周期处理器,发布 ContextRefreshedEvent
事件。
/**
* Finish the refresh of this context, invoking the LifecycleProcessor's
* onRefresh() method and publishing the
* {@link org.springframework.context.event.ContextRefreshedEvent}.
*/
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// 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);
}
4 总结
执行完 refresh
方法,Spring 容器的启动流程就结束了,这里大概介绍了容器启动过程中的一些主要的流程框架,一些细节没有具体去分析,后续会挑一些重要的部分进行分析总结。