Spring IoC容器的初始化过程
Posted 1900
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring IoC容器的初始化过程相关的知识,希望对你有一定的参考价值。
Spring IoC容器的初始化包括 BeanDefinition的Resource定位、载入和注册 这三个基本的过程。IoC容器的初始化过程不包含Bean依赖注入的实现。Bean依赖的注入一般会发生在第一次通过getBean向容器索取Bean的时候。
先看以下代码:
ApplicationContext context = new ClassPathXmlApplicationContext("ioc.xml");
Car car = (Car) context.getBean("car");
System.out.println(car.getBrand());
以上是我们常用的加载IoC容器,并获得Bean的代码。直接进入ClassPathXmlApplicationContext的构造方法,它实际调用的构造方法为:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); //调用容器的refresh,载入BeanDefinitionde的入口。 } }
调用super(parent)方法为容器设置好Bean资源加载器,该方法最终会调用到AbstractApplicationContext的无参构造方法,这里会默认设置解析路径的模式为Ant-style。
setConfigLocations(configLocations)设置Bean定义资源文件的定位路径。AbstractRefreshableConfigApplicationContext中的setConfigLocation(String location)说明了多个资源文件路径之间可以是用” ,
; /t/n”分隔。setConfigLocations(String… locations)说明了它还接受字符串数组。
接下来看下最重要的refresh()方法。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识 prepareRefresh(); // 通知子类启动refreshBeanFactory()的调用 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //为BeanFactory配置容器特性,例如类加载器、事件处理器等 prepareBeanFactory(beanFactory); try { //为子类设置BeanFactory的后置处理器 postProcessBeanFactory(beanFactory); //调用BeanFactoryPostProcessor,这些后置处理器都是在Bean定义中向容器定义的 invokeBeanFactoryPostProcessors(beanFactory); // 注册Bean的后置处理器,在Bean创建过程中调用 registerBeanPostProcessors(beanFactory); // 对上下文的消息源进行初始化 initMessageSource(); // 初始化上下文的事件机制 initApplicationEventMulticaster(); // 初始化其他特殊的Bean onRefresh(); // 检查监听Bean,并且将这些Bean向容器中注册 registerListeners(); // 实例化所有的(non-lazy-init) 单例 finishBeanFactoryInitialization(beanFactory); // 最后一步:发布容器事件,结束refresh过程 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } /销毁已经创建的单态Bean destroyBeans(); // 重置\'active\'状态 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(); } } }
我们重点看ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();。这句代码的作用是告诉子类启动refreshBeanFactory方法以及通过getBeanFactory获得beanFactory。
refreshBeanFactory方法在AbstractApplicationContext中被定义,且在其子类AbstractRefreshableApplicationContext中实现。代码如下:
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { //如果已经有BeanFactory,销毁bean,关闭BeanFactory destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); //创建IoC容器 beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); //启动对BeanDefinitions的载入 synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
通过createBeanFactory()构建了一个DefaultListableBeanFactory IoC容器提供给ApplicationContext使用。同时通过loadBeanDefinitions(beanFactory)载入Bean定义。
loadBeanDefinitions方法的具体实现是在AbstractXmlApplicationContext中。
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { //创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context\'s resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); //为Bean读取器设置Spring资源加载器 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制 initBeanDefinitionReader(beanDefinitionReader); //通过beanDefinitionReader加载BeanDefinitions loadBeanDefinitions(beanDefinitionReader); }
在loadBeanDefinitions中创建了XmlBeanDefinitionReader实例,然后在IoC容器中设置该实例,最后通过loadBeanDefinitions方法来完成Bean定义在IoC容器中的载入。接下来看下真正实现加载BeanDefinitions的loadBeanDefinitions(beanDefinitionReader)方法:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); //获得Bean配置文件的资源位置 if (configResources != null) { //读取AbstractBeanDefinitionReader中定位的资源 reader.loadBeanDefinitions(configResources); } //获取ClassPathXmlApplicationContext构造方法中setConfigLocations方法设置的资源 String[] configLocations = getConfigLocations(); if (configLocations != null) { //读取AbstractBeanDefinitionReader中定位的资源,最终还是以Resource的形式去加载资源。 reader.loadBeanDefinitions(configLocations); } }
在AbstractBeanDefinitionReader的loadBeanDefinitions中开始进行BeanDefinitions的载入。
@Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { counter += loadBeanDefinitions(resource); } return counter; }
以上代码中的loadBeanDefinitions在AbstractBeanDefinitionReader中并没有实现,它只是一个在BeanDefinitionReader中定义的接口方法,具体的实现在各个子类(如:XmlBeanDefinitionReader)中。
在XmlBeanDefinitionReader中实现的loadBeanDefinitions方法会得到一个XML文件的InputStream,然后会获得一个InputResource,调用doLoadBeanDefinitions(inputSource, encodedResource.getResource())返回。doLoadBeanDefinitions方法是去从XML文件中加载BeanDefinitions,具体的过程是在该方法调用了registerBeanDefinitions(doc, resource)。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //这里得到BeanDefinitionDocumentReader来对XML的BeanDefinition进行解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); //具体的解析过程在registerBeanDefinitions中完成 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
通过上面的代码可以知道具体的解析XML并转换为容器内部结构的过程是在BeanDefinitionDocumentReader中完成的,registerBeanDefinitions还对载入的Bean数量进行了统计。这里使用的documentReader是通过createBeanDefinitionDocumentReader()方法创建的默认的DefaultBeanDefinitionDocumentReader。而DefaultBeanDefinitionDocumentReader中定义了Spring的Bean规则。
@Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
在doRegisterBeanDefinitions中,由BeanDefinitionParserDelegate实现了解析过程。
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
通过一路跟进parseBeanDefinitions方法,可以找到以下代码:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } } //这里是处理BeanDefinition的地方,具体的处理工作交给了BeanDefinitionParserDelegate的parseBeanDefinitionElement。 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { //向IoC容器注册解析到BeanDefinition BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name \'" + bdHolder.getBeanName() + "\'", ele, ex); } // 在BeanDefinition想IoC容器注册完以后,发送消息。 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
在processBeanDefinition方法中处理BeanDefinitions,具体的处理工作交给了BeanDefinitionParserDelegate的parseBeanDefinitionElement,并且得到结果BeanDefinitionHolder,然后向IoC容器注册解析到的BeanDefinition,注册完成之后发送消息。BeanDefinitionParserDelegate类包含了对各种Spring Bean定义规则的处理。BeanDefinitionHolder是BeanDefinition的封装类,封装了BeanDefinition,Bean的名字、别名。用它来完成想IoC容器注册。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { //在这里取得<bean>中定义的id、name、aliase属性的值 String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML \'id\' specified - using \'" + beanName + "\' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } //这个方法会引发对Bean元素的详细解析 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML \'id\' nor \'name\' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
以下代码是对Bean元素的详细解析:
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); //这里只是读取定义的<bean>中设置的class名字,然后载入到BeanDefinition中去,只是做个记录,并不涉及对象的实例化过程,对象的实例化实际上是在依赖注入时完成的 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } //这里生成需要的BeanDefinition对象,为Bean定义信息的载入做准备 AbstractBeanDefinition bd = createBeanDefinition(className, parent); //这里对当前的Bean元素进行属性解析,并设置description parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //对各种<bean>元素的信息进行解析 parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析<bean>的构造函数设置 parseConstructorArgElements(ele, bd); //解析<bean>的property设置 parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } //这里是异常处理。 catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }
以上就是BeanDefinition在IoC容器中的载入和解析过程。
在上面的DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法中我们看到有这么一行代码:BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());。这里的作用是想IoC容器注册解析后获得到的BeanDefinition。通过追踪代码,发现DefaultListableBeanFactory实现了在BeanDefinitionRegistry中定义的registerBeanDefinition方法。
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { //检查是不是有相同名字的Bean在IoC容器中存在了 if (!isAllowBeanDefinitionOverriding()) { //存在相同的名字的Bean,但又不允许覆盖,那么会抛出异常 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean \'" + beanName + "\': There is already [" + oldBeanDefinition + "] bound."); } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean \'" + beanName + "\' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean \'" + beanName + "\' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean \'" + beanName + "\' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { //这边是正常注册BeanDefinition。 if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
总结:
IoC容器初始化的入口是在构造方法中调用refresh()开始的。
通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader的实现。
创建的IoC容器是DefaultListableBeanFactory。
IoC容器对Bean的管理和依赖注入功能的实现是通过对其持有的BeanDefinition进行相关操作来完成的。
通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册。
XmlBeanDefinitionReader是BeanDefinitionReader的实现类,通过它来解析XML配置中的bean定义。
实际的处理过程是委托给 BeanDefinitionParserDelegate来完成的。得到bean的定义信息,这些信息在Spring中使用BeanDefinition对象来表示。
BeanDefinition的注册是由BeanDefinitionRegistry实现的registerBeanDefinition方法进行的。内部使用ConcurrentHashMap来保存BeanDefinition。
以上是关于Spring IoC容器的初始化过程的主要内容,如果未能解决你的问题,请参考以下文章