IOC源码解析 通过查看源码,可以得到BeanFactory是Spring的顶级接口。
它提供了一些getBean的方法,它的容器继承体系图,如下所示:
通过其接⼝设计,可以看ApplicationContext除了继承BeanFactory的⼦接⼝,还继承了ResourceLoader(加载资源,用于读取文件等)、MessageSource(国际化)等接⼝,因此其提供的功能也就更丰富了。
IOC容器初始化流程 准备工作 通过对示例代码进行断点,可以看到多个关键节点的发起位置,都是位于同一个方法:
进入此文件,找到对应的方法,可以看到里面有很多方法,对应了生命周期中的各个节点:
接下来需要去官网进行源码下载,然后导入idea,查看源码。
IOC容器初始化 常见的Spring启动方式分为两种:ClassPathApplicationContext和AnnotationConfigApplicationContext; 一种以配置文件方式启动,一种是以注解方式启动;
XML配置方式 ClassPathApplicationContext查看源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 public ClassPathXmlApplicationContext ( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super (parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
通过源码发现,最终是调用了AbstractApplicationContext的refresh方法。
AbstractApplicationContext 查看AbstractApplicationContext类中的refresh方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 @Override public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
通过梳理发现,refresh方法中主要逻辑为:
BeanFactory的初始化,以及加载BeanDefinition;
BeanFactoryPostProcessor的处理;
注册BeanPostProcessor;
执行finishBeanFactoryInitialization方法;
BeanFactory创建流程 通过断点,可以发现ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 最终进入的是AbstractRefreshableApplicationContext类,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 protected final void refreshBeanFactory () throws BeansException { if (this .hasBeanFactory()) { this .destroyBeans(); this .closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = this .createBeanFactory(); beanFactory.setSerializationId(this .getId()); this .customizeBeanFactory(beanFactory); this .loadBeanDefinitions(beanFactory); synchronized (this .beanFactoryMonitor) { this .beanFactory = beanFactory; } } catch (IOException var5) { throw new ApplicationContextException("I/O error parsing bean definition source for " + this .getDisplayName(), var5); } }
时序图如下:
BeanDefinitions加载流程 从上面可知,BeanDefinitions的加载流程是从this.loadBeanDefinitions(beanFactory);开始,然后进入了AbstractXmlApplicationContext的loadBeanDefinitions方法,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 protected void loadBeanDefinitions (DefaultListableBeanFactory beanFactory) throws BeansException, IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setEnvironment(this .getEnvironment()); beanDefinitionReader.setResourceLoader(this ); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this )); this .initBeanDefinitionReader(beanDefinitionReader); this .loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions (XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = this .getConfigResources(); if (configResources != null ) { reader.loadBeanDefinitions(configResources); } String[] configLocations = this .getConfigLocations(); if (configLocations != null ) { reader.loadBeanDefinitions(configLocations); } }
时序图如下所示:
经过XML解析器解析,然后调用BeanDefinitionReaderUtils注册BeanDefinition,最终进入默认的DefaultListableBeanFactory工厂中,将BeanDefinition保存在map中
注解方式 AnnotationConfigApplicationContext查看源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public AnnotationConfigApplicationContext () { this .reader = new AnnotatedBeanDefinitionReader(this ); this .scanner = new ClassPathBeanDefinitionScanner(this ); } public AnnotationConfigApplicationContext (Class<?>... componentClasses) { this (); register(componentClasses); refresh(); } public AnnotationConfigApplicationContext (String... basePackages) { this (); scan(basePackages); refresh(); }
可以发现,注解模式是首先进行包扫描或者类注册,然后也是进入了AbstractApplicationContext的refresh方法。 根据调用时传入参数不同,如果是传入包路径则使用默认无参构造中的scanner,如果是注解扫描配置类则使用无参构造的reader,完成BeanDefinition注册。
BeanDefinition加载流程 时序图如下:
BeanFactory创建流程 注解模式也是进入AbstractApplicationContext的refresh方法,代码和XML配置调用的是一样的。但是BeanFactory创建是不一样的,注解模式使用的是GenericApplicationContext类,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { private final DefaultListableBeanFactory beanFactory; @Nullable private ResourceLoader resourceLoader; private boolean customClassLoader = false ; private final AtomicBoolean refreshed = new AtomicBoolean(); public GenericApplicationContext () { this .beanFactory = new DefaultListableBeanFactory(); } public GenericApplicationContext (DefaultListableBeanFactory beanFactory) { Assert.notNull(beanFactory, "BeanFactory must not be null" ); this .beanFactory = beanFactory; } ...... @Override protected final void refreshBeanFactory () throws IllegalStateException { if (!this .refreshed.compareAndSet(false , true )) { throw new IllegalStateException( "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once" ); } this .beanFactory.setSerializationId(getId()); } ...... }
可以看到在构造方法中,已经赋值了DefaultListableBeanFactory,和XML配置模式使用的是一样的。
Bean创建流程 非懒加载 根据上面的源码解析,可知Bean创建流程的起点是AbstractApplicationContext#refresh()⽅法的finishBeanFactoryInitialization(beanFactory) 处:
进入这个方法中,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 protected void finishBeanFactoryInitialization (ConfigurableListableBeanFactory beanFactory) { ...... ...... beanFactory.setTempClassLoader(null ); beanFactory.freezeConfiguration(); beanFactory.preInstantiateSingletons(); }
可以看到调用了DefaultListableBeanFactory类的preInstantiateSingletons⽅法,部分源码如下,可以看到⼯⼚Bean或者普通Bean,最终都是通过getBean的⽅法获取实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @Override public void preInstantiateSingletons () throws BeansException { ...... List<String> beanNames = new ArrayList<>(this .beanDefinitionNames); 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) { final 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); } } } ...... }
时序图如下:
懒加载
懒加载:即初始化时不进行加载,只有在第一次执行getBean去获取Bean对象时,才会执行加载
根据上面Bean加载流程的源码分析,它只加载了非抽象类、单例、非延迟的bean,所以可以看到在getBean()之前,懒加载的Bean返回的是null:
当getBean()执行完之后,懒加载的Bean也就完成加载:
通过查看源码,可以看到具体的流程如下:
当传入的是BeanName时,进入AbstractBeanFactory类中的getBean()方法,源码如下:
最终进入AbstractBeanFactory类中的doGetBean()方法,然后后续就和Bean加载流程一致,完成加载;
当传入的是BeanClass时,则会进入DefaultListableBeanFactory类的resolveBean()方法,源码如下:
返回之前,调用了resolveNameBean()方法,源码如下: