この記事では Spring-IOC コンテナの概要 (コード付き) を紹介します。これは一定の参考価値があります。必要な友人はそれを参照できます。お役に立てば幸いです。
Spring IoC コンテナによる Bean 定義リソースの読み込みは、refresh() 関数から開始されます。refresh() はテンプレート メソッドです。refresh() メソッドの機能は次のとおりです。コンテナが存在する場合は、更新後に新しく確立された IoC コンテナが使用されるように、既存のコンテナを破棄して閉じる必要があります。リフレッシュの機能はIoCコンテナの再起動と似ており、新しく作成したコンテナでコンテナを初期化し、Bean定義リソースをロードします
public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) { //调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识 this.prepareRefresh(); //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从 //子类的refreshBeanFactory()方法启动 //这个bean的载入过程 包括对xml的解析和加载为BeanDefinitions 都是从this.obtainFreshBeanFactory()这里进入 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); /*这之后的代码都是注册容器的信息源和生命周期事件*/ //为BeanFactory配置容器特性,例如类加载器、事件处理器等 this.prepareBeanFactory(beanFactory); try { //为容器的某些子类指定特殊的BeanPost事件处理器 this.postProcessBeanFactory(beanFactory); //调用所有注册的BeanFactoryPostProcessor的Bean this.invokeBeanFactoryPostProcessors(beanFactory); //为BeanFactory注册BeanPost事件处理器. //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件 this.registerBeanPostProcessors(beanFactory); //初始化信息源,和国际化相关. this.initMessageSource(); //初始化容器事件传播器. this.initApplicationEventMulticaster(); //调用子类的某些特殊Bean初始化方法 this.onRefresh(); //为事件传播器注册事件监听器. this.registerListeners(); //初始化所有剩余的单态Bean. this.finishBeanFactoryInitialization(beanFactory); //初始化容器的生命周期事件处理器,并发布容器的生命周期事件 this.finishRefresh(); } catch (BeansException var9) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } //销毁以创建的单态Bean this.destroyBeans(); //取消refresh操作,重置容器的同步标识. this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } }
AbstractRefreshableApplicationContextクラス:
AbstractRefreshableApplicationContextは抽象的なもののみ定義していますloadBeanDefinitionsメソッド、何コンテナーが実際に呼び出すのは、そのサブクラス AbstractXmlApplicationContext
protected final void refreshBeanFactory() throws BeansException { //如果已经创建了BeanFactory,则销毁并关闭BeanFactory if (this.hasBeanFactory()) { this.destroyBeans(); this.closeBeanFactory(); } try { //创建了一个IOC容器 DefaultListableBeanFactory beanFactory = this.createBeanFactory(); beanFactory.setSerializationId(this.getId()); /对IoC容器进行定制化,如设置启动参数,开启注解的自动装配等 this.customizeBeanFactory(beanFactory); //调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器 this.loadBeanDefinitions(beanFactory); Object var2 = this.beanFactoryMonitor; synchronized(this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException var5) { throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5); } }
AbstractXmlApplicationContext クラスによるこのメソッドの実装です。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { //创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setEnvironment(this.getEnvironment()); //为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的 //祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器 beanDefinitionReader.setResourceLoader(this); //为Bean读取器设置SAX xml解析器 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制 this.initBeanDefinitionReader(beanDefinitionReader); //Bean读取器真正实现加载的方法 this.loadBeanDefinitions(beanDefinitionReader); } protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) { reader.setValidating(this.validating); } 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); } } @Nullable protected Resource[] getConfigResources() { return null; }
読み込みプロセスは、その抽象親クラス AbstractBeanDefinitionReader
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { //获取resourceLoader ResourceLoader resourceLoader = this.getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } else { int loadCount; if (!(resourceLoader instanceof ResourcePatternResolver)) { //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源 //加载多个指定位置的Bean定义资源文件 完成具体的资源定位的工作 Resource resource = resourceLoader.getResource(location); //加载资源 开始我们的第二步操作 转换为BeanDefinition对象 loadCount = this.loadBeanDefinitions((Resource)resource); if (actualResources != null) { actualResources.add(resource); } if (this.logger.isDebugEnabled()) { this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } else { try { //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源 //加载单个指定位置的Bean定义资源文件 Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location); //加载资源 开始我们的第二步操作 转换为BeanDefinition对象 loadCount = this.loadBeanDefinitions(resources); if (actualResources != null) { Resource[] var6 = resources; int var7 = resources.length; for(int var8 = 0; var8 < var7; ++var8) { Resource resource = var6[var8]; actualResources.add(resource); } } if (this.logger.isDebugEnabled()) { this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException var10) { throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10); } } } }
Specific で定義されます。リソースのロード方法
まず、リソースローダーのリソース取得メソッド resourceLoader.getResource(location) を呼び出して、ロードするリソースを取得します。
第 2 に、実際のロード関数は、そのサブクラス XmlBeanDefinitionReader のloadBeanDefinitions メソッドです。
リソースの場所はここで終了します。最終的に返されるのは、BeanDefinition をロードするための Resource オブジェクトです。位置決めが完了すると、BeanDefinition
に対して Maker I/O 条件がロードされますが、具体的なロードはまだ開始されていません。
public Resource getResource(String location) { Assert.notNull(location, "Location must not be null"); Iterator var2 = this.protocolResolvers.iterator(); Resource resource; do { if (!var2.hasNext()) { //处理/开头的定位 if (location.startsWith("/")) { return this.getResourceByPath(location); } //带有classpath标识的Resource if (location.startsWith("classpath:")) { return new ClassPathResource(location.substring("classpath:".length()), this.getClassLoader()); } try { //处理URL标识的Resource定位 URL url = new URL(location); return (Resource)(ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url)); } catch (MalformedURLException var5) { //如果不存classpath、Url、/标志的 就教给他处理 return this.getResourceByPath(location); } } ProtocolResolver protocolResolver = (ProtocolResolver)var2.next(); resource = protocolResolver.resolve(location, this); } while(resource == null); return resource; }
protected Resource getResourceByPath(String path) { if (path != null && path.startsWith("/")) { path = path.substring(1); } //这里使用文件系统资源对象来定义bean 文件 return new FileSystemResource(path); }
BeanDefinition のロードは 2 つの部分に分かれています。最初に、XML パーサーを通じてドキュメント オブジェクトが取得されます。
ただし、これらのドキュメント オブジェクトは Spring の Bean ルールに従って解析されません。 XMLの解析が完了すると、SpringのBeanルールに従って解析が行われますが、この解析処理はdocumentReaderに実装されています。
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { //获取resourceLoader ResourceLoader resourceLoader = this.getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } else { int loadCount; if (!(resourceLoader instanceof ResourcePatternResolver)) { //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源 //加载多个指定位置的Bean定义资源文件 完成具体的资源定位的工作 Resource resource = resourceLoader.getResource(location); //加载资源 开始我们的第二步操作 转换为BeanDefinition对象 loadCount = this.loadBeanDefinitions((Resource)resource); if (actualResources != null) { actualResources.add(resource); } if (this.logger.isDebugEnabled()) { this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } else { try { //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源 //加载单个指定位置的Bean定义资源文件 Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location); //加载资源 开始我们的第二步操作 转换为BeanDefinition对象 loadCount = this.loadBeanDefinitions(resources); if (actualResources != null) { Resource[] var6 = resources; int var7 = resources.length; for(int var8 = 0; var8 < var7; ++var8) { Resource resource = var6[var8]; actualResources.add(resource); } } if (this.logger.isDebugEnabled()) { this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException var10) { throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10); } } } }
xmlファイルをドキュメントオブジェクトに変換し、BeanDefinitionを解析します
Bean定義リソースファイルをXML形式で読み込む方法です
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if(this.logger.isInfoEnabled()) { this.logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get(); if(currentResources == null) { currentResources = new HashSet(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if(!((Set)currentResources).add(encodedResource)) { throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } else { int var5; try { //将资源文件转为InputStream的IO流 InputStream inputStream = encodedResource.getResource().getInputStream(); try { //从InputStream中得到XML的解析源 InputSource inputSource = new InputSource(inputStream); if(encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //这里是具体的读取过程 var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { //IO流的关闭 inputStream.close(); } } catch (IOException var15) { throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15); } finally { ((Set)currentResources).remove(encodedResource); if(((Set)currentResources).isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } return var5; } }
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //@1将XML文件转换为DOM对象,解析过程由documentLoader实现 Document doc = this.doLoadDocument(inputSource, resource); //@2这里是启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean配置规则 return this.registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException var4) { throw var4; } catch (SAXParseException var5) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5); } catch (SAXException var6) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6); } catch (ParserConfigurationException var7) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7); } catch (IOException var8) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8); } catch (Throwable var9) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9); } }
@1
//使用标准的JAXP将载入的Bean定义资源转换成document对象 public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { //创建文件解析器工厂 DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware); if(logger.isDebugEnabled()) { logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); } //创建文档解析器 DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler); //解析Spring的Bean定义资源 return builder.parse(inputSource); } protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException { //创建文档解析工厂 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(namespaceAware); if(validationMode != 0) { //设置解析XML的校验 factory.setValidating(true); if(validationMode == 3) { factory.setNamespaceAware(true); try { factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); } catch (IllegalArgumentException var6) { ParserConfigurationException pcex = new ParserConfigurationException("Unable to validate using XSD: Your JAXP provider [" + factory + "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? Upgrade to Apache Xerces (or Java 1.5) for full XSD support."); pcex.initCause(var6); throw pcex; } } } return factory; }
Spring IoCコンテナを元に、見つかったBean定義リソースファイルを読み込み、読み込み、Documentオブジェクトに変換して処理が完了します。
以下は、Spring IoC コンテナがロードされた Bean 定義リソース ファイルを Document オブジェクトに変換し、それを Spring IoC 管理対象 Bean オブジェクトに解析してコンテナに登録する方法です。
@2
//按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { /得到BeanDefinitionDocumentReader来对xml格式的BeanDefinition解析 BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader(); //获得容器中注册的Bean数量 int countBefore = this.getRegistry().getBeanDefinitionCount(); //解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口 //具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成 //@1 documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource)); /统计解析的Bean数量 return this.getRegistry().getBeanDefinitionCount() - countBefore; } //创建BeanDefinitionDocumentReader对象,解析Document对象 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return (BeanDefinitionDocumentReader)BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); }
DefaultBeanDefinitionDocumentReader はドキュメント オブジェクトを解析し、Spring Beanの定義規則に従って BeanDefinition に変換します
@1
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { public static final String BEAN_ELEMENT = "bean"; public static final String NESTED_BEANS_ELEMENT = "beans"; public static final String ALIAS_ELEMENT = "alias"; public static final String NAME_ATTRIBUTE = "name"; public static final String ALIAS_ATTRIBUTE = "alias"; public static final String IMPORT_ELEMENT = "import"; public static final String RESOURCE_ATTRIBUTE = "resource"; public static final String PROFILE_ATTRIBUTE = "profile"; protected final Log logger = LogFactory.getLog(this.getClass()); private XmlReaderContext readerContext; private BeanDefinitionParserDelegate delegate; public DefaultBeanDefinitionDocumentReader() { } //根据Spring DTD对Bean的定义规则解析Bean定义Document对象 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { //获得XML描述符 this.readerContext = readerContext; this.logger.debug("Loading bean definitions"); //获得Document的根元素 Element root = doc.getDocumentElement(); this.doRegisterBeanDefinitions(root); } protected final XmlReaderContext getReaderContext() { return this.readerContext; } protected Object extractSource(Element ele) { return this.getReaderContext().extractSource(ele); } //具体的解析过程由BeanDefinitionParserDelegate实现, //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素 protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = this.createDelegate(this.getReaderContext(), root, parent); if(this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute("profile"); if(StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; "); if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if(this.logger.isInfoEnabled()) { this.logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource()); } return; } } } //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性 this.preProcessXml(root); //从Document的根元素开始进行Bean定义的Document对象 this.parseBeanDefinitions(root, this.delegate); //在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性 this.postProcessXml(root); this.delegate = parent; } //创建BeanDefinitionParserDelegate,用于完成真正的解析过程 protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); //BeanDefinitionParserDelegate初始化Document根元素 delegate.initDefaults(root, parentDelegate); return delegate; } //使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //Bean定义的Document对象使用了Spring默认的XML命名空间 if(delegate.isDefaultNamespace(root)) { //获取Bean定义的Document对象根元素的所有子节点 NodeList nl = root.getChildNodes(); for(int i = 0; i < nl.getLength(); ++i) { Node node = nl.item(i); //获得Document节点是XML元素节点 if(node instanceof Element) { Element ele = (Element)node; //Bean定义的Document的元素节点使用的是Spring默认的XML命名空间 if(delegate.isDefaultNamespace(ele)) { //使用Spring的Bean规则解析元素节点 this.parseDefaultElement(ele, delegate); } else { //没有使用Spring默认的XML命名空间,则使用用户自定义的解//析规则解析元素节点 delegate.parseCustomElement(ele); } } } } else { //Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的 //解析规则解析Document根节点 delegate.parseCustomElement(root); } } private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //如果元素节点是<Import>导入元素,进行导入解析 if(delegate.nodeNameEquals(ele, "import")) { this.importBeanDefinitionResource(ele); } else if(delegate.nodeNameEquals(ele, "alias")) { //如果元素节点是<Alias>别名元素,进行别名解析 this.processAliasRegistration(ele); } else if(delegate.nodeNameEquals(ele, "bean")) { //元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素, //按照Spring的Bean规则解析元素 this.processBeanDefinition(ele, delegate); } else if(delegate.nodeNameEquals(ele, "beans")) { //如果元素节点是<beans>元素注册为BeanDefintion this.doRegisterBeanDefinitions(ele); } } //解析<Import>导入元素,从给定的导入路径加载Bean定义资源到Spring IoC容器中 protected void importBeanDefinitionResource(Element ele) { /获取给定的导入元素的location属性 String location = ele.getAttribute("resource"); if(!StringUtils.hasText(location)) { this.getReaderContext().error("Resource location must not be empty", ele); } else { //获取location的值 location = this.getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); Set<Resource> actualResources = new LinkedHashSet(4); //标识给定的导入元素的location是否是绝对路径 boolean absoluteLocation = false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException var11) { ; } int importCount; if(absoluteLocation) { try { //使用资源读入器加载给定路径的Bean定义资源 importCount = this.getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if(this.logger.isDebugEnabled()) { this.logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException var10) { this.getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, var10); } } else { //给定的导入元素的location是相对路径 try { Resource relativeResource = this.getReaderContext().getResource().createRelative(location); if(relativeResource.exists()) { //使用资源读入器加载Bean定义资源 importCount = this.getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { String baseLocation = this.getReaderContext().getResource().getURL().toString(); importCount = this.getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources); } if(this.logger.isDebugEnabled()) { this.logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]"); } } catch (IOException var8) { this.getReaderContext().error("Failed to resolve current resource location", ele, var8); } catch (BeanDefinitionStoreException var9) { this.getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, var9); } } //在解析完<Import>元素之后,发送容器导入其他资源处理完成事件 Resource[] actResArray = (Resource[])actualResources.toArray(new Resource[actualResources.size()]); this.getReaderContext().fireImportProcessed(location, actResArray, this.extractSource(ele)); } } //解析<Alias>别名元素,为Bean向Spring IoC容器注册别名 protected void processAliasRegistration(Element ele) { //获取<Alias>别名元素中name的属性值 String name = ele.getAttribute("name"); //获取<Alias>别名元素中alias的属性值 String alias = ele.getAttribute("alias"); boolean valid = true; if(!StringUtils.hasText(name)) { this.getReaderContext().error("Name must not be empty", ele); valid = false; } if(!StringUtils.hasText(alias)) { this.getReaderContext().error("Alias must not be empty", ele); valid = false; } if(valid) { try { //向容器的资源读入器注册别名 this.getReaderContext().getRegistry().registerAlias(name, alias); } catch (Exception var6) { this.getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, var6); } //在解析完<Alias>元素之后,发送容器别名处理完成事件 this.getReaderContext().fireAliasRegistered(name, alias, this.extractSource(ele)); } } //解析Bean定义资源Document对象的普通元素 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类 //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if(bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { //向Spring IoC容器注册解析得到的Bean定义,这是Bean定义向IoC容器注册的入口 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException var5) { this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5); } //在完成向Spring IoC容器注册解析得到的Bean定义之后,发送注册事件 this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } } protected void preProcessXml(Element root) { } protected void postProcessXml(Element root) { } }
上記の Spring IoC コンテナがロードされた Bean 定義ドキュメントを解析していることからわかるように、 Spring を使用する場合、Spring 構成ファイルの
以下は、Bean 要素の解析プロセスです。
//解析Bean定义资源文件中的<Bean>元素,这个方法中主要处理<Bean>元素的id,name public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { //获取id属性 String id = ele.getAttribute("id"); //获取name属性 String nameAttr = ele.getAttribute("name"); List<String> aliases = new ArrayList(); //将Bean元素的name属性全部放到alias属性里面 if(StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; "); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if(!StringUtils.hasText(id) && !aliases.isEmpty()) { beanName = (String)aliases.remove(0); if(this.logger.isDebugEnabled()) { this.logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if(containingBean == null) { //检查bean元素的id和name是否是唯一的 this.checkNameUniqueness(beanName, aliases, ele); } //详细对<Bean>元素中配置的Bean定义进行解析的地方 AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean); if(beanDefinition != null) { if(!StringUtils.hasText(beanName)) { try { if(containingBean != null) { //判断如果没有id和name属性时候是否包含子元素的<Bean> beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true); } else { //如果<Bean>元素中没有配置id、别名或者name,且包含了子//<Bean>元素,为解析的Bean使用别名向IoC容器注册 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(this.logger.isDebugEnabled()) { this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]"); } } catch (Exception var9) { this.error(var9.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } else { return null; } } //详细解析bean元素的地方 public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; //是否包含class属性 if(ele.hasAttribute("class")) { //获取class属性值 不做实例化,bean的实例化是在第一次获取bean的时候完成,这里只获取class的值 className = ele.getAttribute("class").trim(); } try { String parent = null; //如果<Bean>元素中配置了parent属性,则获取parent属性的值 if(ele.hasAttribute("parent")) { parent = ele.getAttribute("parent"); } //根据<Bean>元素配置的class名称和parent属性值创建BeanDefinition //为载入Bean定义信息做准备 AbstractBeanDefinition bd = this.createBeanDefinition(className, parent); //对当前的<Bean>元素中配置的一些属性进行解析和设置,如配置的单态(singleton)属性等 this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); //为<Bean>元素解析的Bean设置description信息 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description")); //对<Bean>元素的meta(元信息)属性解析 this.parseMetaElements(ele, bd); //对<Bean>元素的lookup-method属性解析 this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //对<Bean>元素的replaced-method属性解析 this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析<Bean>元素的构造方法设置 this.parseConstructorArgElements(ele, bd); //解析<Bean>元素的<property>设置 this.parsePropertyElements(ele, bd); //解析<Bean>元素的qualifier属性 this.parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(this.extractSource(ele)); AbstractBeanDefinition var7 = bd; return var7; } catch (ClassNotFoundException var13) { this.error("Bean class [" + className + "] not found", ele, var13); } catch (NoClassDefFoundError var14) { this.error("Class that bean class [" + className + "] depends on not found", ele, var14); } catch (Throwable var15) { this.error("Unexpected failure during bean definition parsing", ele, var15); } finally { this.parseState.pop(); } return null; }
上記のソース コードを分析すると、Spring の
注:
上記の方法では、メタ情報 (meta) や修飾子などの一部の構成の解析は、Spring で構成する場合にはあまり使用されません。Spring の
BeanDefinitionReaderUtils の registerBeanDefinition メソッドを呼び出して、解析された Bean を IoC コンテナに登録します。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if(bdHolder != null) { //通过对document对象的解析和封装返回一个BeanDefinitionHolder bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { //通过这个holder来注册bean对象 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException var5) { this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5); } this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
BeanDefinitionReaderUtils を呼び出して、解析された BeanDefinition を IoC コンテナに登録する場合、実際に登録を完了するのは DefaultListableBeanFactory です。関数。
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); String[] aliases = definitionHolder.getAliases(); if(aliases != null) { String[] var4 = aliases; int var5 = aliases.length; for(int var6 = 0; var6 < var5; ++var6) { String alias = var4[var6]; registry.registerAlias(beanName, alias); } } }
DefaultListableBeanFactory registerBeanDefinition メソッド
//存储注册的俄BeanDefinition private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256); //向IoC容器注册解析的BeanDefiniton 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"); //校验解析的BeanDefiniton if(beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition)beanDefinition).validate(); } catch (BeanDefinitionValidationException var9) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9); } } BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName); if(oldBeanDefinition != null) { if(!this.isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } if(oldBeanDefinition.getRole() < beanDefinition.getRole()) { 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 { if(this.hasBeanCreationStarted()) { Map var4 = this.beanDefinitionMap; //注册的过程中需要线程同步,以保证数据的一致性 synchronized(this.beanDefinitionMap) { //把bean存放到map中 this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if(this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if(oldBeanDefinition != null || this.containsSingleton(beanName)) { this.resetBeanDefinition(beanName); } }
この時点で、Bean 定義リソース ファイルに設定された Bean が解析された後、IoC コンテナに登録され、コンテナによって管理されます。 IoC コンテナの初期化が完了しました。すべての作業が完了しました。これで、Bean の構成情報全体が IoC コンテナに確立されました。この BeanDefinition 情報はすでに利用可能であり、取得することができます。IoC コンテナの役割は、これらの登録された Bean 定義情報を処理および維持することです。これらの登録されたBean定義情報はIoCコンテナの制御反転の基礎となり、コンテナはこれらの登録データを利用して依存性注入を行うことができます。
この記事はここで終了しています。その他のエキサイティングなコンテンツについては、PHP 中国語 Web サイトの Java ビデオ チュートリアル 列に注目してください。
以上がSpring-IOC コンテナの概要 (コード付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。