VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Java教程 >
  • Spring 5 源码解析- XML中Bean配置加载

spring-framework 加载配置文件过程:

        根据业务系统运行的环境,选择 ApplicationContext 接口合适的实现类,启动系统先初始化上下文环境,然后通过BeanDefinitionReader 的实现类读取Bean的配置文件。这里配置文件可以是 xml文件,properties文件,yml文件等,也可以是注解形式扫描配置。配置文件读取成功后,将相应的配置转换成 BeanDefinition 的对象实例保存在DefaultListableBeanFactory#beanDefinitionMap 中。紧接着,根据配置的 BeanFactoryPostProcessor 对象列表,进行 BeanDefinition 的扩展处理。(  例如 org.springframework.beans.factory.config.PlaceholderConfigurerSupport:  ${} 配置转换成实际的值实现类。org.springframework.beans.factory.config.PropertyOverrideConfigurer: 将 beanName.property 替换成实际的值。 )  

 

                                                                               -->   xml配置

                                                                               |

ApplicationContext ---> BeanDefinitionReader -+----> yml配置 -----> BeanDefinition ---> DefaultListableBeanFactory  --->  BeanFactoryPostProcessor 

                                                                               |

                                                                               --> Annotation 扫描

 

    这里以 XML 配置的BeanDefinition 进行源码加载分析:

一. BeanFactory 实例的创建

      在 AbstractApplicationContext#obtainFreshBeanFactory 方法中,是进行 bean 处理的入口。

            AbstractApplicationContext#obtainFreshBeanFactory

                   -> AbstractRefreshableApplicationContext#refreshBeanFactory

        1.检测是否已经创建 BeanFactory 。如果创建了则销毁BeanFactory 相关的属性。

        2.创建 BeanFactory 接口的默认实现类  DefaultListableBeanFactory 实例。

        3.客户化 BeanFactory 处理。

        4.加载 BeanDefinition 定义信息。

复制代码
 1     /**
 2      * This implementation performs an actual refresh of this context's underlying
 3      * bean factory, shutting down the previous bean factory (if any) and
 4      * initializing a fresh bean factory for the next phase of the context's lifecycle.
 5      */
 6     @Override
 7     protected final void refreshBeanFactory() throws BeansException {
 8         if (hasBeanFactory()) {
 9             destroyBeans();
10             closeBeanFactory();
11         }
12         try {
13             DefaultListableBeanFactory beanFactory = createBeanFactory();
14             beanFactory.setSerializationId(getId());
15             customizeBeanFactory(beanFactory);
16             loadBeanDefinitions(beanFactory);
17             this.beanFactory = beanFactory;
18         }
19         catch (IOException ex) {
20             throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
21         }
22     }
复制代码

 

二. ApplicationContex 读取 BeanDefinition 的加载分析

        这里我们分析 XML 形式配置的加载,因此通过 AbstractXmlApplicationContext 来分析源码。

            AbstractApplicationContext#obtainFreshBeanFactory

                   -> AbstractRefreshableApplicationContext#refreshBeanFactory

                      --> AbstractXmlApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)

        1.首先创建读取 BeanDefinition 的 BeanDefinitionReader 接口实现 XmlBeanDefinitionReader 实例,并设置环境信息。

        2.通过 BeanDefinitionReader  实现读取 BeanDefinition  配置信息。

 

复制代码
 1     /**
 2      * Loads the bean definitions via an XmlBeanDefinitionReader.
 3      * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
 4      * @see #initBeanDefinitionReader
 5      * @see #loadBeanDefinitions
 6      */
 7     @Override
 8     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
 9         // Create a new XmlBeanDefinitionReader for the given BeanFactory.
10         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
11 
12         // Configure the bean definition reader with this context's
13         // resource loading environment.
14         beanDefinitionReader.setEnvironment(this.getEnvironment());
15         beanDefinitionReader.setResourceLoader(this);
16         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
17 
18         // Allow a subclass to provide custom initialization of the reader,
19         // then proceed with actually loading the bean definitions.
20         initBeanDefinitionReader(beanDefinitionReader);
21         loadBeanDefinitions(beanDefinitionReader);
22     }
复制代码

 

三. BeanDefinitionReader 读取,加载 BeanDefinition 配置分析

        AbstractXmlApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)

              --> AbstractXmlApplicationContext#loadBeanDefinitions(XmlBeanDefinitionReader)

                      --> AbstractBeanDefinitionReader#loadBeanDefinitions(String, Set<Resource>)

                           --> XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource)

                             --> XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource, Resource )

 

         1.读取 XML 文件,获取到  Document 实例。为后续解析配置做准备。

         2.向 BeanFactory 中注册 BeanDefinition 配置信息。

           此处异常捕获比较多,学习异常规范处理。最底层的 Throwable 异常也捕获了,保证程序不会异常退出。

复制代码
 1     /**
 2      * Actually load bean definitions from the specified XML file.
 3      * @param inputSource the SAX InputSource to read from
 4      * @param resource the resource descriptor for the XML file
 5      * @return the number of bean definitions found
 6      * @throws BeanDefinitionStoreException in case of loading or parsing errors
 7      * @see #doLoadDocument
 8      * @see #registerBeanDefinitions
 9      */
10     protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
11             throws BeanDefinitionStoreException {
12 
13         try {
14             Document doc = doLoadDocument(inputSource, resource);
15             int count = registerBeanDefinitions(doc, resource);
16             if (logger.isDebugEnabled()) {
17                 logger.debug("Loaded " + count + " bean definitions from " + resource);
18             }
19             return count;
20         }
21         catch (BeanDefinitionStoreException ex) {
22             throw ex;
23         }
24         catch (SAXParseException ex) {
25             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
26                     "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
27         }
28         catch (SAXException ex) {
29             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
30                     "XML document from " + resource + " is invalid", ex);
31         }
32         catch (ParserConfigurationException ex) {
33             throw new BeanDefinitionStoreException(resource.getDescription(),
34                     "Parser configuration exception parsing XML from " + resource, ex);
35         }
36         catch (IOException ex) {
37             throw new BeanDefinitionStoreException(resource.getDescription(),
38                     "IOException parsing XML document from " + resource, ex);
39         }
40         catch (Throwable ex) {
41             throw new BeanDefinitionStoreException(resource.getDescription(),
42                     "Unexpected exception parsing XML document from " + resource, ex);
43         }
44     }
复制代码

 

四.BeanDefinitionDocumentReader 解析  BeanDefinition 配置分析

       (一) BeanDefinitionDocumentReader 分析

            XmlBeanDefinitionReader#doLoadBeanDefinitions

                 --> XmlBeanDefinitionReader#registerBeanDefinitions(Document, Resource)

                      -->  BeanDefinitionDocumentReader#registerBeanDefinitionsregisterBeanDefinitions(Document, XmlReaderContext)

            1. 创建 BeanDefinitionDocumentReader  对象实例。

            2.创建 读取 BeanDefinition  配置信息Document的上下文(XmlReaderContext),为后续解析配置提供相关支持。

            3. 解析并注册Document 中配置的 BeanDefinition  信息。在 DefaultBeanDefinitionDocumentReader 实现具体逻辑。

复制代码
 1     /**
 2      * Register the bean definitions contained in the given DOM document.
 3      * Called by {@code loadBeanDefinitions}.
 4      * <p>Creates a new instance of the parser class and invokes
 5      * {@code registerBeanDefinitions} on it.
 6      * @param doc the DOM document
 7      * @param resource the resource descriptor (for context information)
 8      * @return the number of bean definitions found
 9      * @throws BeanDefinitionStoreException in case of parsing errors
10      * @see #loadBeanDefinitions
11      * @see #setDocumentReaderClass
12      * @see BeanDefinitionDocumentReader#registerBeanDefinitions
13      */
14     public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
15         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
16         int countBefore = getRegistry().getBeanDefinitionCount();
17         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
18         return getRegistry().getBeanDefinitionCount() - countBefore;
19     }
复制代码

       (二)BeanDefinitionDocumentReader 实现类 DefaultBeanDefinitionDocumentReader分析

        BeanDefinitionDocumentReader#registerBeanDefinitionsregisterBeanDefinitions(Document, XmlReaderContext)

            -->  DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

                -->  DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element)

       1. 根据 ReaderContext 信息,创建对应的 实例。

       2. 检查 profile 配置信息。如果不匹配,则不解析当前root节点下的 BeanDefinition  配置。 

       3. 当前root节点 前置处理。

       4. 解析当前 root 节点的 BeanDefinition  配置信息。

       5. 当前root节点 后置处理。

    (三)   DefaultBeanDefinitionDocumentReader#parseBeanDefinitions 分析

                DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

                        -->  DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 

                        -->  BeanDefinitionParserDelegate#parseCustomElement(Element)

         1. 判断 root 节点 DefaultNamespace 是否是 http://www.springframework.org/schema/beans 。

                 如果是,则遍历子节点进行解析。

                        当子节点 是 DefaultNamespace 。则使用  DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 解析节点。

                        否做使用  BeanDefinitionParserDelegate#parseCustomElement(Element) 解析节点。

         2. 非默认 DefaultNamespace 值,则使用 BeanDefinitionParserDelegate#parseCustomElement(Element) 解析节点。

                       例如 AOP 配置节点解析。例如:<aop:config>

                       事物配置节点解析。例如:<tx:annotation-driven proxy-target-class="true" />

       (四) 解析 DefaultNamespace 节点 BeanDefinition 信息。

              DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 

                       -->  DefaultBeanDefinitionDocumentReader#importBeanDefinitionResource(Element)

                       --> DefaultBeanDefinitionDocumentReader#processAliasRegistration(Element)

                       --> DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)

                       --> DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element)

              1.依次解析 import  节点,alias 节点,bean节点, beans节点 定义的 BeanDefinition 信息。

       (五) 解析 非默认命名空间节点 BeanDefinition 信息。

                  BeanDefinitionParserDelegate#parseCustomElement(Element)

                       --> BeanDefinitionParserDelegate#parseCustomElement(Element, BeanDefinition)

                  1.获取节点命名空间。

                  2.根据命名空间获取对应的解析器。

                  3. 解析节点 BeanDefinition 信息。

复制代码
 1     /**
 2      * Parse a custom element (outside of the default namespace).
 3      * @param ele the element to parse
 4      * @param containingBd the containing bean definition (if any)
 5      * @return the resulting bean definition
 6      */
 7     @Nullable
 8     public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
 9         String namespaceUri = getNamespaceURI(ele);
10         if (namespaceUri == null) {
11             return null;
12         }
13         NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
14         if (handler == null) {
15             error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
16             return null;
17         }
18         return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
19     }
复制代码

 

五.BeanDefinitionDocumentReader 解析  bean 节点

     XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource)

           --> XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource, Resource)

                 --> XmlBeanDefinitionReader#registerBeanDefinitions(Document, Resource)

                       --> DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document, XmlReaderContext)

                            --> DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element)

                                 -->  DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element , BeanDefinitionParserDelegate)

                                       --> DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element, BeanDefinitionParserDelegate) 

                                             --> DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)

        

       1.使用 BeanDefinitionParserDelegate 解析 Bean 配置节点,得到保存 BeanDefinition 信息的辅助对象 BeanDefinitionHolder 实例。

       2.当 解析的 Bean 配置 BeanDefinitionHolder 实例不为空,则进行 Bean 配置 后续处理。

              a. 当 Bean 配置节点 找到 其他 Namespace 对应 处理器(NamespaceHandler),则进行特殊化处理。

              b. 向 BeanFactory 中注册解析成功的 BeanDefinition 定义。

              c.发送 BeanDefinition 解析成功事件 BeanComponentDefinition。

复制代码
 1     /**
 2      * Process the given bean element, parsing the bean definition
 3      * and registering it with the registry.
 4      */
 5     protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
 6         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
 7         if (bdHolder != null) {
 8             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
 9             try {
10                 // Register the final decorated instance.
11                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
12             }
13             catch (BeanDefinitionStoreException ex) {
14                 getReaderContext().error("Failed to register bean definition with name '" +
15                         bdHolder.getBeanName() + "'", ele, ex);
16             }
17             // Send registration event.
18             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
19         }
20     }
复制代码

 

 六. BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition) 解析  bean 节点

       DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)

             --> BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element) 

                 --> BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element, BeanDefinition)

          1.解析 Element  元素的 id 和 name 属性,得到 beanName 和 aliases。

          2.检查 beanName 是否唯一。

          3. 创建 AbstractBeanDefinition 对象实例 bd ,并通过依次解析 Element  元素的属性给 bd 赋值。

             依次解析子节点 meta, lookup-method, replaced-method, constructor-arg, property, qualifier,并将解析后的值添加到 bd 相关变量。

             设置 bd 解析资源的相关信息。

          4. 如果 3 解析失败,则返回的 实例BeanDefinition 为 null,则这里也直接返回。

          5. 当上述步骤解析的 beanName 为 空时,使用指定方式生成 beanName。

                   当前 bean 是在其他Bean 内部时, 使用BeanDefinitionReaderUtils#generateBeanName(BeanDefinition, BeanDefinitionRegistry, boolean)   生成 beanName。

                   否则使用 XmlReaderContext 对应生成器生成 beanName。

          6.根据解析的 BeanDefinition 创建对应的 BeanDefinitionHolder 对象实例。

         

          在解析 bean 配置信息时,主要有如下 七个元数据包装类,对相关属性配置进行归档:

org.springframework.beans.factory.config.ConstructorArgumentValues  <constructor-arg>

org.springframework.beans.PropertyValue  <property>

org.springframework.beans.factory.support.ManagedArray     <array>

org.springframework.beans.factory.support.ManagedList        <list>

org.springframework.beans.factory.support.ManagedSet        <set>

org.springframework.beans.factory.support.ManagedMap       <map>

org.springframework.beans.factory.support.ManagedProperties   <props>

         每个配置具体字符串值对应了如下三种 处理类型: 

org.springframework.beans.factory.config.TypedStringValue   <value>

org.springframework.beans.factory.config.RuntimeBeanReference     <ref>

org.springframework.beans.factory.config.RuntimeBeanNameReference  <idref>

复制代码
 1     /**
 2      * Parses the supplied {@code <bean>} element. May return {@code null}
 3      * if there were errors during parse. Errors are reported to the
 4      * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
 5      */
 6     @Nullable
 7     public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
 8         String id = ele.getAttribute(ID_ATTRIBUTE);
 9         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
10 
11         List<String> aliases = new ArrayList<>();
12         if (StringUtils.hasLength(nameAttr)) {
13             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
14             aliases.addAll(Arrays.asList(nameArr));
15         }
16 
17         String beanName = id;
18         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
19             beanName = aliases.remove(0);
20             if (logger.isTraceEnabled()) {
21                 logger.trace("No XML 'id' specified - using '" + beanName +
22                         "' as bean name and " + aliases + " as aliases");
23             }
24         }
25 
26         if (containingBean == null) {
27             checkNameUniqueness(beanName, aliases, ele);
28         }
29 
30         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
31         if (beanDefinition != null) {
32             if (!StringUtils.hasText(beanName)) {
33                 try {
34                     if (containingBean != null) {
35                         beanName = BeanDefinitionReaderUtils.generateBeanName(
36                                 beanDefinition, this.readerContext.getRegistry(), true);
37                     }
38                     else {
39                         beanName = this.readerContext.generateBeanName(beanDefinition);
40                         // Register an alias for the plain bean class name, if still possible,
41                         // if the generator returned the class name plus a suffix.
42                         // This is expected for Spring 1.2/2.0 backwards compatibility.
43                         String beanClassName = beanDefinition.getBeanClassName();
44                         if (beanClassName != null &&
45                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
46                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
47                             aliases.add(beanClassName);
48                         }
49                     }
50                     if (logger.isTraceEnabled()) {
51                         logger.trace("Neither XML 'id' nor 'name' specified - " +
52                                 "using generated bean name [" + beanName + "]");
53                     }
54                 }
55                 catch (Exception ex) {
56                     error(ex.getMessage(), ele);
57                     return null;
58                 }
59             }
60             String[] aliasesArray = StringUtils.toStringArray(aliases);
61             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
62         }
63 
64         return null;
65     }
复制代码

 

 七.  BeanDefinitionParserDelegate#decorateIfRequired(Node, BeanDefinitionHolder, @Nullable BeanDefinition)解析  bean 节点自定义属性

       DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)

             --> BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element) 

                 --> BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(Element, BeanDefinitionHolder)

                    --> BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(Element, BeanDefinitionHolder, BeanDefinition)

                         -->  BeanDefinitionParserDelegate#decorateIfRequired(Node, BeanDefinitionHolder, @Nullable BeanDefinition)

           1. 获得节点(Node) 的命名空间URI(NamespaceURI)。

           2. 如果命名空间URI不是默认的,则进行特殊处理。

           3. 通过 命名空间URI 到读取文件上下文(XmlReaderContext) 中查找对应 处理器(NamespaceHandler)。

                例如

                   Context的处理器: org.springframework.context.config.ContextNamespaceHandler

                        AOP的处理器:  org.springframework.aop.config.AopNamespaceHandler

              component的处理器: org.springframework.beans.factory.xml.ComponentNamespaceHandler

           4. 调用 NamespaceHandler#decorate(Node, BeanDefinitionHolder, ParserContext)方法解析 节点配置信息,并返回新的 BeanDefinitionHolder 实例。 

复制代码
 1     /**
 2      * Decorate the given bean definition through a namespace handler,
 3      * if applicable.
 4      * @param node the current child node
 5      * @param originalDef the current bean definition
 6      * @param containingBd the containing bean definition (if any)
 7      * @return the decorated bean definition
 8      */
 9     public BeanDefinitionHolder decorateIfRequired(
10             Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
11 
12         String namespaceUri = getNamespaceURI(node);
13         if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
14             NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
15             if (handler != null) {
16                 BeanDefinitionHolder decorated =
17                         handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
18                 if (decorated != null) {
19                     return decorated;
20                 }
21             }
22             else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
23                 error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
24             }
25             else {
26                 // A custom namespace, not to be handled by Spring - maybe "xml:...".
27                 if (logger.isDebugEnabled()) {
28                     logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
29                 }
30             }
31         }
32         return originalDef;
33     }
复制代码

 

 八. BeanDefinitionReaderUtils#registerBeanDefinition(BeanDefinitionHolder, BeanDefinitionRegistry) 向 BeanFactory 注册 BeanDefinition 实例信息

       1. 通过 beanName 向 beanFactory 中注册 BeanDefinition 实例。

       2. 通过 beanName 向 beanFactory 中注册 BeanDefinition 实例的别名列表。

复制代码
 1     /**
 2      * Register the given bean definition with the given bean factory.
 3      * @param definitionHolder the bean definition including name and aliases
 4      * @param registry the bean factory to register with
 5      * @throws BeanDefinitionStoreException if registration failed
 6      */
 7     public static void registerBeanDefinition(
 8             BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
 9             throws BeanDefinitionStoreException {
10 
11         // Register bean definition under primary name.
12         String beanName = definitionHolder.getBeanName();
13         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
14 
15         // Register aliases for bean name, if any.
16         String[] aliases = definitionHolder.getAliases();
17         if (aliases != null) {
18             for (String alias : aliases) {
19                 registry.registerAlias(beanName, alias);
20             }
21         }
22     }
复制代码

 

-----------------------------------------------------
作者:流羽          经流年 看繁花似锦 望星辰不变
出处:https://www.cnblogs.com/StreamPlume/p/15673202.html


相关教程