spring IOC容器源码分析
spring IOC容器源码学习
我先介绍一下这篇文章的整体情况,首先我会介绍IOC容器的整体的框架逻辑,然后通过ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationfile.xml");
这段代码来一步步的分析IOC容器的调用流程。通过将IOC分为初始化,注入依赖两部分来进行分析
初始化
初始化的主要过程包括xml文件的读取,读取内容的解析,以及最终注册到BeanFactory
先使用最基本启动IOC容器的例子
public class springTest1 { public static void main(String[] args){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml"); } }
maven包的引用,spring-context 会自动将 spring-core、spring-beans、spring-aop、spring-expression 这几个基础 jar 包带进来。如果需要查看spring各个包对应哪些功能可以查看spring各模块之间的关系以及依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.12.RELEASE</version> </dependency>
在接着下面的内容讲解之前,我们首先来看一下spring IOC容器各个接口类之间的继承关系
从上面的结构图我们可以看出来,ClassPathXmlApplicationContext
经过了很多层接口的实现才到达ApplicationContext
。其中FileSystemXmlApplicationContext
与ClassPathXmlApplicationContext
功能基本相同。
AnnotationConfigApplicationContext
是基于注解来使用的,它不需要配置文件,采用 java 配置类和各种注解来配置。
BeanFactory 简介
BeanFactory是生产bean的工厂,负责生产和管理各个 bean 实例。其中的ApplicationContext其实就是一个BeanFactory,不过BeanFactory是最基本的容器,而ApplicationContext是一个高级容器,实现了很多高级的功能
ApplicationContext
继承了ListableBeanFactory
,这个Listable
的意思就是,通过这个接口,我们可以获取多个Bean
,大家看源码会发现,最顶层BeanFactory
接口的方法都是获取单个Bean
的。ApplicationContext
继承了HierarchicalBeanFactory
,Hierarchical
单词本身已经能说明问题了,也就是说我们可以在应用中起多个BeanFactory
,然后可以将各个BeanFactory
设置为父子关系。AutowireCapableBeanFactory
这个名字中的Autowire
大家都非常熟悉,它就是用来自动装配Bean
用的,但是仔细看上图,ApplicationContext
并没有继承它,不过不用担心,不使用继承,不代表不可以使用组合,如果你看到ApplicationContext
接口定义中的最后一个方法getAutowireCapableBeanFactory()
就知道了。ConfigurableListableBeanFactory
也是一个特殊的接口,看图,特殊之处在于它继承了第二层所有的三个接口,而ApplicationContext
没有。这点之后会用到。
准备
保存配置位置,并刷新
在调用ClassPathXmlApplicationContext
的构造方法的时候,首先调用setConfigLocations
方法,将配置文件的地址信息保存到configLocations数组中。之后会调用refresh
方法进行刷新,该方法会将ApplicationContext
销毁,重新执行一次初始化操作。
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { private Resource[] configResources; // 如果已经有 ApplicationContext 并需要配置成父子关系,那么调用这个构造方法 public ClassPathXmlApplicationContext(ApplicationContext parent) { super(parent); } ... public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); // 根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割) setConfigLocations(configLocations); if (refresh) { refresh(); // 核心方法 } } ... }
@Override public void refresh() throws BeansException, IllegalStateException { // 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛 synchronized (this.startupShutdownMonitor) { // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符 prepareRefresh(); // 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中, // 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了, // 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean // 这块待会会展开说 prepareBeanFactory(beanFactory); try { // 【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口, // 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】 // 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化 // 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事 postProcessBeanFactory(beanFactory); // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法 invokeBeanFactoryPostProcessors(beanFactory); // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别 // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化 registerBeanPostProcessors(beanFactory); // 初始化当前 ApplicationContext 的 MessageSource,国际化这里就不展开说了,不然没完没了了 initMessageSource(); // 初始化当前 ApplicationContext 的事件广播器,这里也不展开了 initApplicationEventMulticaster(); // 从方法名就可以知道,典型的模板方法(钩子方法), // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前) onRefresh(); // 注册事件监听器,监听器需要实现 ApplicationListener 接口。这也不是我们的重点,过 registerListeners(); // 重点,重点,重点 // 初始化所有的 singleton beans //(lazy-init 的除外) finishBeanFactoryInitialization(beanFactory); // 最后,广播事件,ApplicationContext 初始化完成 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. // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源 destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // 把异常往外抛 throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
创建载入BeanFactory
,通过执行refresh
方法中的prepareRefresh
方法中的refreshBeanFactory
方法,创建载入方法由AbstractRefreshableApplicationContext.java
类实现
//AbstractRefreshableApplicationContext.java
@Override protected final void refreshBeanFactory() throws BeansException { // 如果 ApplicationContext 中已经加载过 BeanFactory 了,销毁所有 Bean,关闭 BeanFactory // 注意,应用中 BeanFactory 本来就是可以多个的,这里可不是说应用全局是否有 BeanFactory,而是当前 // ApplicationContext 是否有 BeanFactory if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { // 初始化一个 DefaultListableBeanFactory,为什么用这个,我们马上说。 DefaultListableBeanFactory beanFactory = createBeanFactory(); // 用于 BeanFactory 的序列化,我想不部分人应该都用不到 beanFactory.setSerializationId(getId()); // 下面这两个方法很重要,别跟丢了,具体细节之后说 // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用 customizeBeanFactory(beanFactory); // 加载 Bean 到 BeanFactory 中 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
创建XMLBeanDefinitionReader
这个方法将根据配置,加载各个 Bean,然后放到 BeanFactory 中
,XMLBeanDefinitionReader
用来加载配置和解析
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // ... ... // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
读取
创建处理每一个resource
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { // ... ... // 通过Location来读取Resource Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); // ... ... } public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { // 载入每一个resource counter += loadBeanDefinitions(resource); } return counter; }
处理XML每个元素:该功能不做详解,大概就是通过解析xml节点来获取bean的各个参数
解析和注册bean
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 解析 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 注册 // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition( bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
本步骤需要将xml的内容解析成BeanDefinition
,然后存入BeanDefinitionHolder
中,然后利用BeanDefinitionHolder
将BeanDefinition
实例put到BeanFactory中。
注册
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } } public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // ...... // 将beanDefinition注册 this.beanDefinitionMap.put(beanName, beanDefinition); // ...... }
注册过程中,最核心的一句就是:this.beanDefinitionMap.put(beanName, beanDefinition)
,也就是说注册的实质就是以beanName
为key
,以BeanDefinition
为value
,将其put
到HashMap
中。
当完成初始化IOC
容器后,如果Bean
没有设置lazy-init
(延迟加载)属性,那么Bean
的实例就会在初始化IOC
完成之后,及时地进行初始化。初始化时会先建立实例,然后根据配置利用反射对实例进行进一步操作,具体流程如下所示:
在创建bean和注入bean的属性时,都是在doCreateBean函数中进行的,我们重点看下:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // 说明不是 FactoryBean,这里实例化 Bean,这里非常关键,细节之后再说 instanceWrapper = createBeanInstance(beanName, mbd, args); } // 这个就是 Bean 里面的 我们定义的类 的实例,很多地方我直接描述成 "bean 实例" final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); // 类型 Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); mbd.resolvedTargetType = beanType; // 建议跳过吧,涉及接口:MergedBeanDefinitionPostProcessor synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { // MergedBeanDefinitionPostProcessor,这个我真不展开说了,直接跳过吧,很少用的 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. // 下面这块代码是为了解决循环依赖的问题,以后有时间,我再对循环依赖这个问题进行解析吧 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } // Initialize the bean instance. Object exposedObject = bean; try { // 这一步也是非常关键的,这一步负责属性装配,因为前面的实例只是实例化了,并没有设值,这里就是设值 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { // 还记得 init-method 吗?还有 InitializingBean 接口?还有 BeanPostProcessor 接口? // 这里就是处理 bean 初始化完成后的各种回调 exposedObject = initializeBean(beanName, exposedObject, mbd); } } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } if (earlySingletonExposure) { // Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
先看看createBeanInstance
方法,此方法的目的就是实例化我们指定的类populateBean(...)
方法,该方法负责进行属性设值,处理依赖。initializeBean
属性注入完成后,这一步其实就是处理各种回调了