Spring 源码分析(三)--默认标签的解析
一:DefaultBeanDefinitionDocumentReader 解析BeanDefinition
/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.xml; /** * Default implementation of the {@link BeanDefinitionDocumentReader} interface that * reads bean definitions according to the "spring-beans" DTD and XSD format * (Spring's default XML bean definition format). * * <p>The structure, elements, and attribute names of the required XML document * are hard-coded in this class. (Of course a transform could be run if necessary * to produce this format). {@code <beans>} does not need to be the root * element of the XML document: this class will parse all bean definition elements * in the XML file, regardless of the actual root element. * * @author Rod Johnson * @author Juergen Hoeller * @author Rob Harrop * @author Erik Wiersma * @since 18.12.2003 */ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT; 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(getClass()); private XmlReaderContext readerContext; private BeanDefinitionParserDelegate delegate; /** * This implementation parses bean definitions according to the "spring-beans" XSD * (or DTD, historically). * <p>Opens a DOM Document; then initializes the default settings * specified at the {@code <beans/>} level; then parses the contained bean definitions. */ @Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); } /** * Return the descriptor for the XML resource that this parser works on. */ protected final XmlReaderContext getReaderContext() { return this.readerContext; } /** * Invoke the {@link org.springframework.beans.factory.parsing.SourceExtractor} to pull the * source metadata from the supplied {@link Element}. */ protected Object extractSource(Element ele) { return getReaderContext().extractSource(ele); } /** * Register each bean definition within the given root {@code <beans/>} element. */ protected void doRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. 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)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; } protected BeanDefinitionParserDelegate createDelegate( XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); delegate.initDefaults(root, parentDelegate); return delegate; } /** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */ protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } 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); } } /** * Parse an "import" element and load the bean definitions * from the given resource into the bean factory. */ protected void importBeanDefinitionResource(Element ele) { String location = ele.getAttribute(RESOURCE_ATTRIBUTE); if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; } // Resolve system properties: e.g. "${user.dir}" location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); Set<Resource> actualResources = new LinkedHashSet<Resource>(4); // Discover whether the location is an absolute or relative URI boolean absoluteLocation = false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { // cannot convert to an URI, considering the location relative // unless it is the well-known Spring prefix "classpath*:" } // Absolute or relative? if (absoluteLocation) { try { int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException ex) { getReaderContext().error( "Failed to import bean definitions from URL location [" + location + "]", ele, ex); } } else { // No URL -> considering resource location as relative to the current file. try { int importCount; Resource relativeResource = getReaderContext().getResource().createRelative(location); if (relativeResource.exists()) { importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { String baseLocation = getReaderContext().getResource().getURL().toString(); importCount = getReaderContext().getReader().loadBeanDefinitions( StringUtils.applyRelativePath(baseLocation, location), actualResources); } if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]"); } } catch (IOException ex) { getReaderContext().error("Failed to resolve current resource location", ele, ex); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, ex); } } Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]); getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); } /** * Process the given alias element, registering the alias with the registry. */ protected void processAliasRegistration(Element ele) { String name = ele.getAttribute(NAME_ATTRIBUTE); String alias = ele.getAttribute(ALIAS_ATTRIBUTE); boolean valid = true; if (!StringUtils.hasText(name)) { getReaderContext().error("Name must not be empty", ele); valid = false; } if (!StringUtils.hasText(alias)) { getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) { try { getReaderContext().getRegistry().registerAlias(name, alias); } catch (Exception ex) { getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, ex); } getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); } } /** * Process the given bean element, parsing the bean definition * and registering it with the registry. */ 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)); } } /** * Allow the XML to be extensible by processing any custom element types first, * before we start to process the bean definitions. This method is a natural * extension point for any other custom pre-processing of the XML. * <p>The default implementation is empty. Subclasses can override this method to * convert custom elements into standard Spring bean definitions, for example. * Implementors have access to the parser's bean definition reader and the * underlying XML resource, through the corresponding accessors. * @see #getReaderContext() */ protected void preProcessXml(Element root) { } /** * Allow the XML to be extensible by processing any custom element types last, * after we finished processing the bean definitions. This method is a natural * extension point for any other custom post-processing of the XML. * <p>The default implementation is empty. Subclasses can override this method to * convert custom elements into standard Spring bean definitions, for example. * Implementors have access to the parser's bean definition reader and the * underlying XML resource, through the corresponding accessors. * @see #getReaderContext() */ protected void postProcessXml(Element root) { } }
二:BeanDefinitionParserDelegate 解析Element 获取BeanDefinitionHolder
/* * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.xml; /** * Stateful delegate class used to parse XML bean definitions. * Intended for use by both the main parser and any extension * {@link BeanDefinitionParser BeanDefinitionParsers} or * {@link BeanDefinitionDecorator BeanDefinitionDecorators}. * * @author Rob Harrop * @author Juergen Hoeller * @author Rod Johnson * @author Mark Fisher * @author Gary Russell * @since 2.0 * @see ParserContext * @see DefaultBeanDefinitionDocumentReader */ public class BeanDefinitionParserDelegate { public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans"; public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; "; /** * Value of a T/F attribute that represents true. * Anything else represents false. Case seNsItive. */ public static final String TRUE_VALUE = "true"; public static final String FALSE_VALUE = "false"; public static final String DEFAULT_VALUE = "default"; public static final String DESCRIPTION_ELEMENT = "description"; public static final String AUTOWIRE_NO_VALUE = "no"; public static final String AUTOWIRE_BY_NAME_VALUE = "byName"; public static final String AUTOWIRE_BY_TYPE_VALUE = "byType"; public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor"; public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect"; public static final String DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = "all"; public static final String DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE = "simple"; public static final String DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = "objects"; public static final String NAME_ATTRIBUTE = "name"; public static final String BEAN_ELEMENT = "bean"; public static final String META_ELEMENT = "meta"; public static final String ID_ATTRIBUTE = "id"; public static final String PARENT_ATTRIBUTE = "parent"; public static final String CLASS_ATTRIBUTE = "class"; public static final String ABSTRACT_ATTRIBUTE = "abstract"; public static final String SCOPE_ATTRIBUTE = "scope"; private static final String SINGLETON_ATTRIBUTE = "singleton"; public static final String LAZY_INIT_ATTRIBUTE = "lazy-init"; public static final String AUTOWIRE_ATTRIBUTE = "autowire"; public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate"; public static final String PRIMARY_ATTRIBUTE = "primary"; public static final String DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check"; public static final String DEPENDS_ON_ATTRIBUTE = "depends-on"; public static final String INIT_METHOD_ATTRIBUTE = "init-method"; public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method"; public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method"; public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean"; public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg"; public static final String INDEX_ATTRIBUTE = "index"; public static final String TYPE_ATTRIBUTE = "type"; public static final String VALUE_TYPE_ATTRIBUTE = "value-type"; public static final String KEY_TYPE_ATTRIBUTE = "key-type"; public static final String PROPERTY_ELEMENT = "property"; public static final String REF_ATTRIBUTE = "ref"; public static final String VALUE_ATTRIBUTE = "value"; public static final String LOOKUP_METHOD_ELEMENT = "lookup-method"; public static final String REPLACED_METHOD_ELEMENT = "replaced-method"; public static final String REPLACER_ATTRIBUTE = "replacer"; public static final String ARG_TYPE_ELEMENT = "arg-type"; public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match"; public static final String REF_ELEMENT = "ref"; public static final String IDREF_ELEMENT = "idref"; public static final String BEAN_REF_ATTRIBUTE = "bean"; public static final String LOCAL_REF_ATTRIBUTE = "local"; public static final String PARENT_REF_ATTRIBUTE = "parent"; public static final String VALUE_ELEMENT = "value"; public static final String NULL_ELEMENT = "null"; public static final String ARRAY_ELEMENT = "array"; public static final String LIST_ELEMENT = "list"; public static final String SET_ELEMENT = "set"; public static final String MAP_ELEMENT = "map"; public static final String ENTRY_ELEMENT = "entry"; public static final String KEY_ELEMENT = "key"; public static final String KEY_ATTRIBUTE = "key"; public static final String KEY_REF_ATTRIBUTE = "key-ref"; public static final String VALUE_REF_ATTRIBUTE = "value-ref"; public static final String PROPS_ELEMENT = "props"; public static final String PROP_ELEMENT = "prop"; public static final String MERGE_ATTRIBUTE = "merge"; public static final String QUALIFIER_ELEMENT = "qualifier"; public static final String QUALIFIER_ATTRIBUTE_ELEMENT = "attribute"; public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init"; public static final String DEFAULT_MERGE_ATTRIBUTE = "default-merge"; public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire"; public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check"; public static final String DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE = "default-autowire-candidates"; public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = "default-init-method"; public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = "default-destroy-method"; protected final Log logger = LogFactory.getLog(getClass()); private final XmlReaderContext readerContext; private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition(); private final ParseState parseState = new ParseState(); /** * Stores all used bean names so we can enforce uniqueness on a per * beans-element basis. Duplicate bean ids/names may not exist within the * same level of beans element nesting, but may be duplicated across levels. */ private final Set<String> usedNames = new HashSet<String>(); /** * Create a new BeanDefinitionParserDelegate associated with the supplied * {@link XmlReaderContext}. */ public BeanDefinitionParserDelegate(XmlReaderContext readerContext) { Assert.notNull(readerContext, "XmlReaderContext must not be null"); this.readerContext = readerContext; } /** * Get the {@link XmlReaderContext} associated with this helper instance. */ public final XmlReaderContext getReaderContext() { return this.readerContext; } /** * Get the {@link Environment} associated with this helper instance. * @deprecated in favor of {@link XmlReaderContext#getEnvironment()} */ @Deprecated public final Environment getEnvironment() { return this.readerContext.getEnvironment(); } /** * Invoke the {@link org.springframework.beans.factory.parsing.SourceExtractor} to pull the * source metadata from the supplied {@link Element}. */ protected Object extractSource(Element ele) { return this.readerContext.extractSource(ele); } /** * Report an error with the given message for the given source element. */ protected void error(String message, Node source) { this.readerContext.error(message, source, this.parseState.snapshot()); } /** * Report an error with the given message for the given source element. */ protected void error(String message, Element source) { this.readerContext.error(message, source, this.parseState.snapshot()); } /** * Report an error with the given message for the given source element. */ protected void error(String message, Element source, Throwable cause) { this.readerContext.error(message, source, this.parseState.snapshot(), cause); } /** * Initialize the default settings assuming a {@code null} parent delegate. */ public void initDefaults(Element root) { initDefaults(root, null); } /** * Initialize the default lazy-init, autowire, dependency check settings, * init-method, destroy-method and merge settings. Support nested 'beans' * element use cases by falling back to the given parent in case the * defaults are not explicitly set locally. * @see #populateDefaults(DocumentDefaultsDefinition, DocumentDefaultsDefinition, org.w3c.dom.Element) * @see #getDefaults() */ public void initDefaults(Element root, BeanDefinitionParserDelegate parent) { populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root); this.readerContext.fireDefaultsRegistered(this.defaults); } /** * Populate the given DocumentDefaultsDefinition instance with the default lazy-init, * autowire, dependency check settings, init-method, destroy-method and merge settings. * Support nested 'beans' element use cases by falling back to <literal>parentDefaults</literal> * in case the defaults are not explicitly set locally. * @param defaults the defaults to populate * @param parentDefaults the parent BeanDefinitionParserDelegate (if any) defaults to fall back to * @param root the root element of the current bean definition document (or nested beans element) */ protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) { String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { // Potentially inherited from outer <beans> sections, otherwise falling back to false. lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE); } defaults.setLazyInit(lazyInit); String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE); if (DEFAULT_VALUE.equals(merge)) { // Potentially inherited from outer <beans> sections, otherwise falling back to false. merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE); } defaults.setMerge(merge); String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE); if (DEFAULT_VALUE.equals(autowire)) { // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'. autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE); } defaults.setAutowire(autowire); // Don't fall back to parentDefaults for dependency-check as it's no longer supported in // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it. defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE)); if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) { defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates()); } if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) { defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setInitMethod(parentDefaults.getInitMethod()); } if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) { defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setDestroyMethod(parentDefaults.getDestroyMethod()); } defaults.setSource(this.readerContext.extractSource(root)); } /** * Return the defaults definition object, or {@code null} if the * defaults have been initialized yet. */ public DocumentDefaultsDefinition getDefaults() { return this.defaults; } /** * Return the default settings for bean definitions as indicated within * the attributes of the top-level {@code <beans/>} element. */ public BeanDefinitionDefaults getBeanDefinitionDefaults() { BeanDefinitionDefaults bdd = new BeanDefinitionDefaults(); bdd.setLazyInit("TRUE".equalsIgnoreCase(this.defaults.getLazyInit())); bdd.setDependencyCheck(this.getDependencyCheck(DEFAULT_VALUE)); bdd.setAutowireMode(this.getAutowireMode(DEFAULT_VALUE)); bdd.setInitMethodName(this.defaults.getInitMethod()); bdd.setDestroyMethodName(this.defaults.getDestroyMethod()); return bdd; } /** * Return any patterns provided in the 'default-autowire-candidates' * attribute of the top-level {@code <beans/>} element. */ public String[] getAutowireCandidatePatterns() { String candidatePattern = this.defaults.getAutowireCandidates(); return (candidatePattern != null ? StringUtils.commaDelimitedListToStringArray(candidatePattern) : null); } /** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } /** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { 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); } 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); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. 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; } /** * Validate that the specified bean name and aliases have not been used already * within the current level of beans element nesting. */ protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) { String foundName = null; if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) { foundName = beanName; } if (foundName == null) { foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases); } if (foundName != null) { error("Bean name '" + foundName + "' is already used in this <beans> element", beanElement); } this.usedNames.add(beanName); this.usedNames.addAll(aliases); } /** * Parse the bean definition itself, without regard to name or aliases. May return * {@code null} if problems occurred during the parsing of the bean definition. */ public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); 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); }
//创建用于承载AbstractBeanDefinition类型的GenericBeanDefinition AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//硬编码解析默认bean的各种属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析元数据 parseMetaElements(ele, bd);
//解析lookup-method属性 parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析replace-method属性 parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析构造函数参数 parseConstructorArgElements(ele, bd);
//解析property子元素 parsePropertyElements(ele, bd);
//解析qualifier子元素 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; } /** * Apply the attributes of the given bean element to the given bean * definition. * @param ele bean declaration element * @param beanName bean name * @param containingBean containing bean definition * @return a bean definition initialized according to the bean element attributes */ public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); } else if (containingBean != null) { // Take default from containing bean in case of an inner bean definition. bd.setScope(containingBean.getScope()); } if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE); bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); } String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) { String candidatePattern = this.defaults.getAutowireCandidates(); if (candidatePattern != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } else { bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); } if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); } if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) { String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE); if (!"".equals(initMethodName)) { bd.setInitMethodName(initMethodName); } } else { if (this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } } if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) { String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); bd.setDestroyMethodName(destroyMethodName); } else { if (this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } } if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } return bd; } /** * Create a bean definition for the given class name and parent name. * @param className the name of the bean class * @param parentName the name of the bean's parent bean * @return the newly created bean definition * @throws ClassNotFoundException if bean class resolution was attempted but failed */ protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException { return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader()); } public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) { NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) { Element metaElement = (Element) node; String key = metaElement.getAttribute(KEY_ATTRIBUTE); String value = metaElement.getAttribute(VALUE_ATTRIBUTE); BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value); attribute.setSource(extractSource(metaElement)); attributeAccessor.addMetadataAttribute(attribute); } } } @SuppressWarnings("deprecation") public int getAutowireMode(String attValue) { String att = attValue; if (DEFAULT_VALUE.equals(att)) { att = this.defaults.getAutowire(); } int autowire = AbstractBeanDefinition.AUTOWIRE_NO; if (AUTOWIRE_BY_NAME_VALUE.equals(att)) { autowire = AbstractBeanDefinition.AUTOWIRE_BY_NAME; } else if (AUTOWIRE_BY_TYPE_VALUE.equals(att)) { autowire = AbstractBeanDefinition.AUTOWIRE_BY_TYPE; } else if (AUTOWIRE_CONSTRUCTOR_VALUE.equals(att)) { autowire = AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR; } else if (AUTOWIRE_AUTODETECT_VALUE.equals(att)) { autowire = AbstractBeanDefinition.AUTOWIRE_AUTODETECT; } // Else leave default value. return autowire; } public int getDependencyCheck(String attValue) { String att = attValue; if (DEFAULT_VALUE.equals(att)) { att = this.defaults.getDependencyCheck(); } if (DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE.equals(att)) { return AbstractBeanDefinition.DEPENDENCY_CHECK_ALL; } else if (DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE.equals(att)) { return AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS; } else if (DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE.equals(att)) { return AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE; } else { return AbstractBeanDefinition.DEPENDENCY_CHECK_NONE; } } /** * Parse constructor-arg sub-elements of the given bean element. */ public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) { parseConstructorArgElement((Element) node, bd); } } } /** * Parse property sub-elements of the given bean element. */ public void parsePropertyElements(Element beanEle, BeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { parsePropertyElement((Element) node, bd); } } } /** * Parse qualifier sub-elements of the given bean element. */ public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) { parseQualifierElement((Element) node, bd); } } } /** * Parse lookup-override sub-elements of the given bean element. */ public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) { Element ele = (Element) node; String methodName = ele.getAttribute(NAME_ATTRIBUTE); String beanRef = ele.getAttribute(BEAN_ELEMENT); LookupOverride override = new LookupOverride(methodName, beanRef); override.setSource(extractSource(ele)); overrides.addOverride(override); } } } /** * Parse replaced-method sub-elements of the given bean element. */ public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) { Element replacedMethodEle = (Element) node; String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE); String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE); ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); // Look for arg-type match elements. List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT); for (Element argTypeEle : argTypeEles) { String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE); match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle)); if (StringUtils.hasText(match)) { replaceOverride.addTypeIdentifier(match); } } replaceOverride.setSource(extractSource(replacedMethodEle)); overrides.addOverride(replaceOverride); } } } /** * Parse a constructor-arg element. */ public void parseConstructorArgElement(Element ele, BeanDefinition bd) { String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE); String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(indexAttr)) { try { int index = Integer.parseInt(indexAttr); if (index < 0) { error("'index' cannot be lower than 0", ele); } else { try { this.parseState.push(new ConstructorArgumentEntry(index)); Object value = parsePropertyValue(ele, bd, null); ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { error("Ambiguous constructor-arg entries for index " + index, ele); } else { bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); } } finally { this.parseState.pop(); } } } catch (NumberFormatException ex) { error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); } } else { try { this.parseState.push(new ConstructorArgumentEntry()); Object value = parsePropertyValue(ele, bd, null); ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); } finally { this.parseState.pop(); } } } /** * Parse a property element. */ public void parsePropertyElement(Element ele, BeanDefinition bd) { String propertyName = ele.getAttribute(NAME_ATTRIBUTE); if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); try { if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } Object val = parsePropertyValue(ele, bd, propertyName); PropertyValue pv = new PropertyValue(propertyName, val); parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } } /** * Parse a qualifier element. */ public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) { String typeName = ele.getAttribute(TYPE_ATTRIBUTE); if (!StringUtils.hasLength(typeName)) { error("Tag 'qualifier' must have a 'type' attribute", ele); return; } this.parseState.push(new QualifierEntry(typeName)); try { AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName); qualifier.setSource(extractSource(ele)); String value = ele.getAttribute(VALUE_ATTRIBUTE); if (StringUtils.hasLength(value)) { qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value); } NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) { Element attributeEle = (Element) node; String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE); String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE); if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) { BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue); attribute.setSource(extractSource(attributeEle)); qualifier.addMetadataAttribute(attribute); } else { error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle); return; } } } bd.addQualifier(qualifier); } finally { this.parseState.pop(); } } /** * Get the value of a property element. May be a list etc. * Also used for constructor arguments, "propertyName" being null in this case. */ public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // Should only have one child element: ref, value, list, etc. NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { return parsePropertySubElement(subElement, bd); } else { // Neither child element nor "ref" or "value" attribute found. error(elementName + " must specify a ref or value", ele); return null; } } public Object parsePropertySubElement(Element ele, BeanDefinition bd) { return parsePropertySubElement(ele, bd, null); } /** * Parse a value, ref or collection sub-element of a property or * constructor-arg element. * @param ele subelement of property element; we don't know which yet * @param defaultValueType the default type (class name) for any * {@code <value>} tag that might be created */ public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { if (!isDefaultNamespace(ele)) { return parseNestedCustomElement(ele, bd); } else if (nodeNameEquals(ele, BEAN_ELEMENT)) { BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, REF_ELEMENT)) { // A generic reference to any name of any bean. String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in the same XML file. refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in a parent context. refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); toParent = true; if (!StringUtils.hasLength(refName)) { error("'bean', 'local' or 'parent' is required for <ref> element", ele); return null; } } } if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); return null; } RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } else if (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement(ele); } else if (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } else if (nodeNameEquals(ele, NULL_ELEMENT)) { // It's a distinguished null value. Let's wrap it in a TypedStringValue // object in order to preserve the source location. TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement(ele, bd); } else if (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement(ele, bd); } else if (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement(ele, bd); } else if (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement(ele, bd); } else if (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement(ele); } else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } } /** * Return a typed String value Object for the given 'idref' element. */ public Object parseIdRefElement(Element ele) { // A generic reference to any name of any bean. String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in the same XML file. refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { error("Either 'bean' or 'local' is required for <idref> element", ele); return null; } } if (!StringUtils.hasText(refName)) { error("<idref> element contains empty target attribute", ele); return null; } RuntimeBeanNameReference ref = new RuntimeBeanNameReference(refName); ref.setSource(extractSource(ele)); return ref; } /** * Return a typed String value Object for the given value element. */ public Object parseValueElement(Element ele, String defaultTypeName) { // It's a literal value. String value = DomUtils.getTextValue(ele); String specifiedTypeName = ele.getAttribute(TYPE_ATTRIBUTE); String typeName = specifiedTypeName; if (!StringUtils.hasText(typeName)) { typeName = defaultTypeName; } try { TypedStringValue typedValue = buildTypedStringValue(value, typeName); typedValue.setSource(extractSource(ele)); typedValue.setSpecifiedTypeName(specifiedTypeName); return typedValue; } catch (ClassNotFoundException ex) { error("Type class [" + typeName + "] not found for <value> element", ele, ex); return value; } } /** * Build a typed String value Object for the given raw value. * @see org.springframework.beans.factory.config.TypedStringValue */ protected TypedStringValue buildTypedStringValue(String value, String targetTypeName) throws ClassNotFoundException { ClassLoader classLoader = this.readerContext.getBeanClassLoader(); TypedStringValue typedValue; if (!StringUtils.hasText(targetTypeName)) { typedValue = new TypedStringValue(value); } else if (classLoader != null) { Class<?> targetType = ClassUtils.forName(targetTypeName, classLoader); typedValue = new TypedStringValue(value, targetType); } else { typedValue = new TypedStringValue(value, targetTypeName); } return typedValue; } /** * Parse an array element. */ public Object parseArrayElement(Element arrayEle, BeanDefinition bd) { String elementType = arrayEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = arrayEle.getChildNodes(); ManagedArray target = new ManagedArray(elementType, nl.getLength()); target.setSource(extractSource(arrayEle)); target.setElementTypeName(elementType); target.setMergeEnabled(parseMergeAttribute(arrayEle)); parseCollectionElements(nl, target, bd, elementType); return target; } /** * Parse a list element. */ public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) { String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = collectionEle.getChildNodes(); ManagedList<Object> target = new ManagedList<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectionEle)); parseCollectionElements(nl, target, bd, defaultElementType); return target; } /** * Parse a set element. */ public Set<Object> parseSetElement(Element collectionEle, BeanDefinition bd) { String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = collectionEle.getChildNodes(); ManagedSet<Object> target = new ManagedSet<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectionEle)); parseCollectionElements(nl, target, bd, defaultElementType); return target; } protected void parseCollectionElements( NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) { for (int i = 0; i < elementNodes.getLength(); i++) { Node node = elementNodes.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) { target.add(parsePropertySubElement((Element) node, bd, defaultElementType)); } } } /** * Parse a map element. */ public Map<Object, Object> parseMapElement(Element mapEle, BeanDefinition bd) { String defaultKeyType = mapEle.getAttribute(KEY_TYPE_ATTRIBUTE); String defaultValueType = mapEle.getAttribute(VALUE_TYPE_ATTRIBUTE); List<Element> entryEles = DomUtils.getChildElementsByTagName(mapEle, ENTRY_ELEMENT); ManagedMap<Object, Object> map = new ManagedMap<Object, Object>(entryEles.size()); map.setSource(extractSource(mapEle)); map.setKeyTypeName(defaultKeyType); map.setValueTypeName(defaultValueType); map.setMergeEnabled(parseMergeAttribute(mapEle)); for (Element entryEle : entryEles) { // Should only have one value child element: ref, value, list, etc. // Optionally, there might be a key child element. NodeList entrySubNodes = entryEle.getChildNodes(); Element keyEle = null; Element valueEle = null; for (int j = 0; j < entrySubNodes.getLength(); j++) { Node node = entrySubNodes.item(j); if (node instanceof Element) { Element candidateEle = (Element) node; if (nodeNameEquals(candidateEle, KEY_ELEMENT)) { if (keyEle != null) { error("<entry> element is only allowed to contain one <key> sub-element", entryEle); } else { keyEle = candidateEle; } } else { // Child element is what we're looking for. if (nodeNameEquals(candidateEle, DESCRIPTION_ELEMENT)) { // the element is a <description> -> ignore it } else if (valueEle != null) { error("<entry> element must not contain more than one value sub-element", entryEle); } else { valueEle = candidateEle; } } } } // Extract key from attribute or sub-element. Object key = null; boolean hasKeyAttribute = entryEle.hasAttribute(KEY_ATTRIBUTE); boolean hasKeyRefAttribute = entryEle.hasAttribute(KEY_REF_ATTRIBUTE); if ((hasKeyAttribute && hasKeyRefAttribute) || ((hasKeyAttribute || hasKeyRefAttribute)) && keyEle != null) { error("<entry> element is only allowed to contain either " + "a 'key' attribute OR a 'key-ref' attribute OR a <key> sub-element", entryEle); } if (hasKeyAttribute) { key = buildTypedStringValueForMap(entryEle.getAttribute(KEY_ATTRIBUTE), defaultKeyType, entryEle); } else if (hasKeyRefAttribute) { String refName = entryEle.getAttribute(KEY_REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error("<entry> element contains empty 'key-ref' attribute", entryEle); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(entryEle)); key = ref; } else if (keyEle != null) { key = parseKeyElement(keyEle, bd, defaultKeyType); } else { error("<entry> element must specify a key", entryEle); } // Extract value from attribute or sub-element. Object value = null; boolean hasValueAttribute = entryEle.hasAttribute(VALUE_ATTRIBUTE); boolean hasValueRefAttribute = entryEle.hasAttribute(VALUE_REF_ATTRIBUTE); boolean hasValueTypeAttribute = entryEle.hasAttribute(VALUE_TYPE_ATTRIBUTE); if ((hasValueAttribute && hasValueRefAttribute) || ((hasValueAttribute || hasValueRefAttribute)) && valueEle != null) { error("<entry> element is only allowed to contain either " + "'value' attribute OR 'value-ref' attribute OR <value> sub-element", entryEle); } if ((hasValueTypeAttribute && hasValueRefAttribute) || (hasValueTypeAttribute && !hasValueAttribute) || (hasValueTypeAttribute && valueEle != null)) { error("<entry> element is only allowed to contain a 'value-type' " + "attribute when it has a 'value' attribute", entryEle); } if (hasValueAttribute) { String valueType = entryEle.getAttribute(VALUE_TYPE_ATTRIBUTE); if (!StringUtils.hasText(valueType)) { valueType = defaultValueType; } value = buildTypedStringValueForMap(entryEle.getAttribute(VALUE_ATTRIBUTE), valueType, entryEle); } else if (hasValueRefAttribute) { String refName = entryEle.getAttribute(VALUE_REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error("<entry> element contains empty 'value-ref' attribute", entryEle); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(entryEle)); value = ref; } else if (valueEle != null) { value = parsePropertySubElement(valueEle, bd, defaultValueType); } else { error("<entry> element must specify a value", entryEle); } // Add final key and value to the Map. map.put(key, value); } return map; } /** * Build a typed String value Object for the given raw value. * @see org.springframework.beans.factory.config.TypedStringValue */ protected final Object buildTypedStringValueForMap(String value, String defaultTypeName, Element entryEle) { try { TypedStringValue typedValue = buildTypedStringValue(value, defaultTypeName); typedValue.setSource(extractSource(entryEle)); return typedValue; } catch (ClassNotFoundException ex) { error("Type class [" + defaultTypeName + "] not found for Map key/value type", entryEle, ex); return value; } } /** * Parse a key sub-element of a map element. */ protected Object parseKeyElement(Element keyEle, BeanDefinition bd, String defaultKeyTypeName) { NodeList nl = keyEle.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { // Child element is what we're looking for. if (subElement != null) { error("<key> element must not contain more than one value sub-element", keyEle); } else { subElement = (Element) node; } } } return parsePropertySubElement(subElement, bd, defaultKeyTypeName); } /** * Parse a props element. */ public Properties parsePropsElement(Element propsEle) { ManagedProperties props = new ManagedProperties(); props.setSource(extractSource(propsEle)); props.setMergeEnabled(parseMergeAttribute(propsEle)); List<Element> propEles = DomUtils.getChildElementsByTagName(propsEle, PROP_ELEMENT); for (Element propEle : propEles) { String key = propEle.getAttribute(KEY_ATTRIBUTE); // Trim the text value to avoid unwanted whitespace // caused by typical XML formatting. String value = DomUtils.getTextValue(propEle).trim(); TypedStringValue keyHolder = new TypedStringValue(key); keyHolder.setSource(extractSource(propEle)); TypedStringValue valueHolder = new TypedStringValue(value); valueHolder.setSource(extractSource(propEle)); props.put(keyHolder, valueHolder); } return props; } /** * Parse the merge attribute of a collection element, if any. */ public boolean parseMergeAttribute(Element collectionElement) { String value = collectionElement.getAttribute(MERGE_ATTRIBUTE); if (DEFAULT_VALUE.equals(value)) { value = this.defaults.getMerge(); } return TRUE_VALUE.equals(value); } public BeanDefinition parseCustomElement(Element ele) { return parseCustomElement(ele, null); } public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); } public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) { return decorateBeanDefinitionIfRequired(ele, definitionHolder, null); } public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) { BeanDefinitionHolder finalDefinition = definitionHolder; // Decorate based on custom attributes first. NamedNodeMap attributes = ele.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node node = attributes.item(i); finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } // Decorate based on custom nested elements. NodeList children = ele.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } } return finalDefinition; } public BeanDefinitionHolder decorateIfRequired( Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(node); if (!isDefaultNamespace(namespaceUri)) { NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler != null) { return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd)); } else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node); } else { // A custom namespace, not to be handled by Spring - maybe "xml:...". if (logger.isDebugEnabled()) { logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]"); } } } return originalDef; } private BeanDefinitionHolder parseNestedCustomElement(Element ele, BeanDefinition containingBd) { BeanDefinition innerDefinition = parseCustomElement(ele, containingBd); if (innerDefinition == null) { error("Incorrect usage of element '" + ele.getNodeName() + "' in a nested manner. " + "This tag cannot be used nested inside <property>.", ele); return null; } String id = ele.getNodeName() + BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(innerDefinition); if (logger.isDebugEnabled()) { logger.debug("Using generated bean name [" + id + "] for nested custom element '" + ele.getNodeName() + "'"); } return new BeanDefinitionHolder(innerDefinition, id); } /** * Get the namespace URI for the supplied node. * <p>The default implementation uses {@link Node#getNamespaceURI}. * Subclasses may override the default implementation to provide a * different namespace identification mechanism. * @param node the node */ public String getNamespaceURI(Node node) { return node.getNamespaceURI(); } /** * Get the local name for the supplied {@link Node}. * <p>The default implementation calls {@link Node#getLocalName}. * Subclasses may override the default implementation to provide a * different mechanism for getting the local name. * @param node the {@code Node} */ public String getLocalName(Node node) { return node.getLocalName(); } /** * Determine whether the name of the supplied node is equal to the supplied name. * <p>The default implementation checks the supplied desired name against both * {@link Node#getNodeName()} and {@link Node#getLocalName()}. * <p>Subclasses may override the default implementation to provide a different * mechanism for comparing node names. * @param node the node to compare * @param desiredName the name to check for */ public boolean nodeNameEquals(Node node, String desiredName) { return desiredName.equals(node.getNodeName()) || desiredName.equals(getLocalName(node)); } public boolean isDefaultNamespace(String namespaceUri) { return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri)); } public boolean isDefaultNamespace(Node node) { return isDefaultNamespace(getNamespaceURI(node)); } private boolean isCandidateElement(Node node) { return (node instanceof Element && (isDefaultNamespace(node) || !isDefaultNamespace(node.getParentNode()))); } }
三:AbstractBeanDefinition 类
上面完成了对XML文档到GenericBeanDefinition的转换,也就是到这来,XML中所有的配置都可以在GenericBeanDefinition的实例类中找到对应的配置。
GenericBeanDefinition只是子类实现,而大部分的通用属性都保存在了AbstractBeanDefinition中,那么我们再次通过AbstractBeanDefinition的属性来看下解析了哪些对应的配置。
/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.support; /** * Base class for concrete, full-fledged {@link BeanDefinition} classes, * factoring out common properties of {@link GenericBeanDefinition}, * {@link RootBeanDefinition}, and {@link ChildBeanDefinition}. * * <p>The autowire constants match the ones defined in the * {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory} * interface. * * @author Rod Johnson * @author Juergen Hoeller * @author Rob Harrop * @author Mark Fisher * @see GenericBeanDefinition * @see RootBeanDefinition * @see ChildBeanDefinition */ @SuppressWarnings("serial") public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable { /** * Constant for the default scope name: {@code ""}, equivalent to singleton * status unless overridden from a parent bean definition (if applicable). */ public static final String SCOPE_DEFAULT = ""; /** * Constant that indicates no autowiring at all. * @see #setAutowireMode */ public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO; /** * Constant that indicates autowiring bean properties by name. * @see #setAutowireMode */ public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; /** * Constant that indicates autowiring bean properties by type. * @see #setAutowireMode */ public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE; /** * Constant that indicates autowiring a constructor. * @see #setAutowireMode */ public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR; /** * Constant that indicates determining an appropriate autowire strategy * through introspection of the bean class. * @see #setAutowireMode * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies, * use annotation-based autowiring for clearer demarcation of autowiring needs. */ @Deprecated public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT; /** * Constant that indicates no dependency check at all. * @see #setDependencyCheck */ public static final int DEPENDENCY_CHECK_NONE = 0; /** * Constant that indicates dependency checking for object references. * @see #setDependencyCheck */ public static final int DEPENDENCY_CHECK_OBJECTS = 1; /** * Constant that indicates dependency checking for "simple" properties. * @see #setDependencyCheck * @see org.springframework.beans.BeanUtils#isSimpleProperty */ public static final int DEPENDENCY_CHECK_SIMPLE = 2; /** * Constant that indicates dependency checking for all properties * (object references as well as "simple" properties). * @see #setDependencyCheck */ public static final int DEPENDENCY_CHECK_ALL = 3; /** * Constant that indicates the container should attempt to infer the * {@link #setDestroyMethodName destroy method name} for a bean as opposed to * explicit specification of a method name. The value {@value} is specifically * designed to include characters otherwise illegal in a method name, ensuring * no possibility of collisions with legitimately named methods having the same * name. * <p>Currently, the method names detected during destroy method inference * are "close" and "shutdown", if present on the specific bean class. */ public static final String INFER_METHOD = "(inferred)"; private volatile Object beanClass;
//bean的作用范围,对应bean的属性scope private String scope = SCOPE_DEFAULT;
//是否是抽象,对应bean属性abstract private boolean abstractFlag = false;
//是否延迟加载,对应bean属性lazy-init private boolean lazyInit = false;
//自动注入模式,对应bean属性autowire private int autowireMode = AUTOWIRE_NO; private int dependencyCheck = DEPENDENCY_CHECK_NONE; private String[] dependsOn; private boolean autowireCandidate = true;
//自动装配时当出现多个bean候选者时,将作为首选者,对应bean属性primary private boolean primary = false; private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<String, AutowireCandidateQualifier>(0); private boolean nonPublicAccessAllowed = true; private boolean lenientConstructorResolution = true; private String factoryBeanName;
//对应bean属性factory-method private String factoryMethodName;
//记录构造函数注入属性,对应bean属性constructor-arg private ConstructorArgumentValues constructorArgumentValues;
//普通属性集合 private MutablePropertyValues propertyValues; private MethodOverrides methodOverrides = new MethodOverrides();
//初始化方法,对应bean属性init-method private String initMethodName;
//销毁方法,对应bean属性destory-method private String destroyMethodName; private boolean enforceInitMethod = true; private boolean enforceDestroyMethod = true; private boolean synthetic = false; private int role = BeanDefinition.ROLE_APPLICATION; private String description; private Resource resource; /** * Create a new AbstractBeanDefinition with default settings. */ protected AbstractBeanDefinition() { this(null, null); } /** * Create a new AbstractBeanDefinition with the given * constructor argument values and property values. */ protected AbstractBeanDefinition(ConstructorArgumentValues cargs, MutablePropertyValues pvs) { setConstructorArgumentValues(cargs); setPropertyValues(pvs); } /** * Create a new AbstractBeanDefinition as a deep copy of the given * bean definition. * @param original the original bean definition to copy from */ protected AbstractBeanDefinition(BeanDefinition original) { setParentName(original.getParentName()); setBeanClassName(original.getBeanClassName()); setScope(original.getScope()); setAbstract(original.isAbstract()); setLazyInit(original.isLazyInit()); setFactoryBeanName(original.getFactoryBeanName()); setFactoryMethodName(original.getFactoryMethodName()); setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues())); setPropertyValues(new MutablePropertyValues(original.getPropertyValues())); setRole(original.getRole()); setSource(original.getSource()); copyAttributesFrom(original); if (original instanceof AbstractBeanDefinition) { AbstractBeanDefinition originalAbd = (AbstractBeanDefinition) original; if (originalAbd.hasBeanClass()) { setBeanClass(originalAbd.getBeanClass()); } setAutowireMode(originalAbd.getAutowireMode()); setDependencyCheck(originalAbd.getDependencyCheck()); setDependsOn(originalAbd.getDependsOn()); setAutowireCandidate(originalAbd.isAutowireCandidate()); setPrimary(originalAbd.isPrimary()); copyQualifiersFrom(originalAbd); setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed()); setLenientConstructorResolution(originalAbd.isLenientConstructorResolution()); setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides())); setInitMethodName(originalAbd.getInitMethodName()); setEnforceInitMethod(originalAbd.isEnforceInitMethod()); setDestroyMethodName(originalAbd.getDestroyMethodName()); setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod()); setSynthetic(originalAbd.isSynthetic()); setResource(originalAbd.getResource()); } else { setResourceDescription(original.getResourceDescription()); } } /** * Override settings in this bean definition (presumably a copied parent * from a parent-child inheritance relationship) from the given bean * definition (presumably the child). * <ul> * <li>Will override beanClass if specified in the given bean definition. * <li>Will always take {@code abstract}, {@code scope}, * {@code lazyInit}, {@code autowireMode}, {@code dependencyCheck}, * and {@code dependsOn} from the given bean definition. * <li>Will add {@code constructorArgumentValues}, {@code propertyValues}, * {@code methodOverrides} from the given bean definition to existing ones. * <li>Will override {@code factoryBeanName}, {@code factoryMethodName}, * {@code initMethodName}, and {@code destroyMethodName} if specified * in the given bean definition. * </ul> */ public void overrideFrom(BeanDefinition other) { if (StringUtils.hasLength(other.getBeanClassName())) { setBeanClassName(other.getBeanClassName()); } if (StringUtils.hasLength(other.getScope())) { setScope(other.getScope()); } setAbstract(other.isAbstract()); setLazyInit(other.isLazyInit()); if (StringUtils.hasLength(other.getFactoryBeanName())) { setFactoryBeanName(other.getFactoryBeanName()); } if (StringUtils.hasLength(other.getFactoryMethodName())) { setFactoryMethodName(other.getFactoryMethodName()); } getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues()); getPropertyValues().addPropertyValues(other.getPropertyValues()); setRole(other.getRole()); setSource(other.getSource()); copyAttributesFrom(other); if (other instanceof AbstractBeanDefinition) { AbstractBeanDefinition otherAbd = (AbstractBeanDefinition) other; if (otherAbd.hasBeanClass()) { setBeanClass(otherAbd.getBeanClass()); } setAutowireMode(otherAbd.getAutowireMode()); setDependencyCheck(otherAbd.getDependencyCheck()); setDependsOn(otherAbd.getDependsOn()); setAutowireCandidate(otherAbd.isAutowireCandidate()); setPrimary(otherAbd.isPrimary()); copyQualifiersFrom(otherAbd); setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed()); setLenientConstructorResolution(otherAbd.isLenientConstructorResolution()); getMethodOverrides().addOverrides(otherAbd.getMethodOverrides()); if (StringUtils.hasLength(otherAbd.getInitMethodName())) { setInitMethodName(otherAbd.getInitMethodName()); setEnforceInitMethod(otherAbd.isEnforceInitMethod()); } if (otherAbd.getDestroyMethodName() != null) { setDestroyMethodName(otherAbd.getDestroyMethodName()); setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod()); } setSynthetic(otherAbd.isSynthetic()); setResource(otherAbd.getResource()); } else { setResourceDescription(other.getResourceDescription()); } } /** * Apply the provided default values to this bean. * @param defaults the defaults to apply */ public void applyDefaults(BeanDefinitionDefaults defaults) { setLazyInit(defaults.isLazyInit()); setAutowireMode(defaults.getAutowireMode()); setDependencyCheck(defaults.getDependencyCheck()); setInitMethodName(defaults.getInitMethodName()); setEnforceInitMethod(false); setDestroyMethodName(defaults.getDestroyMethodName()); setEnforceDestroyMethod(false); } /** * Specify the bean class name of this bean definition. */ @Override public void setBeanClassName(String beanClassName) { this.beanClass = beanClassName; } /** * Return the current bean class name of this bean definition. */ @Override public String getBeanClassName() { Object beanClassObject = this.beanClass; if (beanClassObject instanceof Class) { return ((Class<?>) beanClassObject).getName(); } else { return (String) beanClassObject; } } /** * Specify the class for this bean. */ public void setBeanClass(Class<?> beanClass) { this.beanClass = beanClass; } /** * Return the class of the wrapped bean, if already resolved. * @return the bean class, or {@code null} if none defined * @throws IllegalStateException if the bean definition does not define a bean class, * or a specified bean class name has not been resolved into an actual Class */ public Class<?> getBeanClass() throws IllegalStateException { Object beanClassObject = this.beanClass; if (beanClassObject == null) { throw new IllegalStateException("No bean class specified on bean definition"); } if (!(beanClassObject instanceof Class)) { throw new IllegalStateException( "Bean class name [" + beanClassObject + "] has not been resolved into an actual Class"); } return (Class<?>) beanClassObject; } /** * Return whether this definition specifies a bean class. */ public boolean hasBeanClass() { return (this.beanClass instanceof Class); } /** * Determine the class of the wrapped bean, resolving it from a * specified class name if necessary. Will also reload a specified * Class from its name when called with the bean class already resolved. * @param classLoader the ClassLoader to use for resolving a (potential) class name * @return the resolved bean class * @throws ClassNotFoundException if the class name could be resolved */ public Class<?> resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException { String className = getBeanClassName(); if (className == null) { return null; } Class<?> resolvedClass = ClassUtils.forName(className, classLoader); this.beanClass = resolvedClass; return resolvedClass; } /** * Set the name of the target scope for the bean. * <p>The default is singleton status, although this is only applied once * a bean definition becomes active in the containing factory. A bean * definition may eventually inherit its scope from a parent bean definition. * For this reason, the default scope name is an empty string (i.e., {@code ""}), * with singleton status being assumed until a resolved scope is set. * @see #SCOPE_SINGLETON * @see #SCOPE_PROTOTYPE */ @Override public void setScope(String scope) { this.scope = scope; } /** * Return the name of the target scope for the bean. */ @Override public String getScope() { return this.scope; } /** * Return whether this a <b>Singleton</b>, with a single shared instance * returned from all calls. * @see #SCOPE_SINGLETON */ @Override public boolean isSingleton() { return SCOPE_SINGLETON.equals(scope) || SCOPE_DEFAULT.equals(scope); } /** * Return whether this a <b>Prototype</b>, with an independent instance * returned for each call. * @see #SCOPE_PROTOTYPE */ @Override public boolean isPrototype() { return SCOPE_PROTOTYPE.equals(scope); } /** * Set if this bean is "abstract", i.e. not meant to be instantiated itself but * rather just serving as parent for concrete child bean definitions. * <p>Default is "false". Specify true to tell the bean factory to not try to * instantiate that particular bean in any case. */ public void setAbstract(boolean abstractFlag) { this.abstractFlag = abstractFlag; } /** * Return whether this bean is "abstract", i.e. not meant to be instantiated * itself but rather just serving as parent for concrete child bean definitions. */ @Override public boolean isAbstract() { return this.abstractFlag; } /** * Set whether this bean should be lazily initialized. * <p>If {@code false}, the bean will get instantiated on startup by bean * factories that perform eager initialization of singletons. */ @Override public void setLazyInit(boolean lazyInit) { this.lazyInit = lazyInit; } /** * Return whether this bean should be lazily initialized, i.e. not * eagerly instantiated on startup. Only applicable to a singleton bean. */ @Override public boolean isLazyInit() { return this.lazyInit; } /** * Set the autowire mode. This determines whether any automagical detection * and setting of bean references will happen. Default is AUTOWIRE_NO, * which means there's no autowire. * @param autowireMode the autowire mode to set. * Must be one of the constants defined in this class. * @see #AUTOWIRE_NO * @see #AUTOWIRE_BY_NAME * @see #AUTOWIRE_BY_TYPE * @see #AUTOWIRE_CONSTRUCTOR * @see #AUTOWIRE_AUTODETECT */ public void setAutowireMode(int autowireMode) { this.autowireMode = autowireMode; } /** * Return the autowire mode as specified in the bean definition. */ public int getAutowireMode() { return this.autowireMode; } /** * Return the resolved autowire code, * (resolving AUTOWIRE_AUTODETECT to AUTOWIRE_CONSTRUCTOR or AUTOWIRE_BY_TYPE). * @see #AUTOWIRE_AUTODETECT * @see #AUTOWIRE_CONSTRUCTOR * @see #AUTOWIRE_BY_TYPE */ public int getResolvedAutowireMode() { if (this.autowireMode == AUTOWIRE_AUTODETECT) { // Work out whether to apply setter autowiring or constructor autowiring. // If it has a no-arg constructor it's deemed to be setter autowiring, // otherwise we'll try constructor autowiring. Constructor<?>[] constructors = getBeanClass().getConstructors(); for (Constructor<?> constructor : constructors) { if (constructor.getParameterTypes().length == 0) { return AUTOWIRE_BY_TYPE; } } return AUTOWIRE_CONSTRUCTOR; } else { return this.autowireMode; } } /** * Set the dependency check code. * @param dependencyCheck the code to set. * Must be one of the four constants defined in this class. * @see #DEPENDENCY_CHECK_NONE * @see #DEPENDENCY_CHECK_OBJECTS * @see #DEPENDENCY_CHECK_SIMPLE * @see #DEPENDENCY_CHECK_ALL */ public void setDependencyCheck(int dependencyCheck) { this.dependencyCheck = dependencyCheck; } /** * Return the dependency check code. */ public int getDependencyCheck() { return this.dependencyCheck; } /** * Set the names of the beans that this bean depends on being initialized. * The bean factory will guarantee that these beans get initialized first. * <p>Note that dependencies are normally expressed through bean properties or * constructor arguments. This property should just be necessary for other kinds * of dependencies like statics (*ugh*) or database preparation on startup. */ @Override public void setDependsOn(String... dependsOn) { this.dependsOn = dependsOn; } /** * Return the bean names that this bean depends on. */ @Override public String[] getDependsOn() { return this.dependsOn; } /** * Set whether this bean is a candidate for getting autowired into some other bean. * <p>Note that this flag is designed to only affect type-based autowiring. * It does not affect explicit references by name, which will get resolved even * if the specified bean is not marked as an autowire candidate. As a consequence, * autowiring by name will nevertheless inject a bean if the name matches. * @see #AUTOWIRE_BY_TYPE * @see #AUTOWIRE_BY_NAME */ @Override public void setAutowireCandidate(boolean autowireCandidate) { this.autowireCandidate = autowireCandidate; } /** * Return whether this bean is a candidate for getting autowired into some other bean. */ @Override public boolean isAutowireCandidate() { return this.autowireCandidate; } /** * Set whether this bean is a primary autowire candidate. * <p>If this value is {@code true} for exactly one bean among multiple * matching candidates, it will serve as a tie-breaker. */ @Override public void setPrimary(boolean primary) { this.primary = primary; } /** * Return whether this bean is a primary autowire candidate. */ @Override public boolean isPrimary() { return this.primary; } /** * Register a qualifier to be used for autowire candidate resolution, * keyed by the qualifier's type name. * @see AutowireCandidateQualifier#getTypeName() */ public void addQualifier(AutowireCandidateQualifier qualifier) { this.qualifiers.put(qualifier.getTypeName(), qualifier); } /** * Return whether this bean has the specified qualifier. */ public boolean hasQualifier(String typeName) { return this.qualifiers.keySet().contains(typeName); } /** * Return the qualifier mapped to the provided type name. */ public AutowireCandidateQualifier getQualifier(String typeName) { return this.qualifiers.get(typeName); } /** * Return all registered qualifiers. * @return the Set of {@link AutowireCandidateQualifier} objects. */ public Set<AutowireCandidateQualifier> getQualifiers() { return new LinkedHashSet<AutowireCandidateQualifier>(this.qualifiers.values()); } /** * Copy the qualifiers from the supplied AbstractBeanDefinition to this bean definition. * @param source the AbstractBeanDefinition to copy from */ public void copyQualifiersFrom(AbstractBeanDefinition source) { Assert.notNull(source, "Source must not be null"); this.qualifiers.putAll(source.qualifiers); } /** * Specify whether to allow access to non-public constructors and methods, * for the case of externalized metadata pointing to those. The default is * {@code true}; switch this to {@code false} for public access only. * <p>This applies to constructor resolution, factory method resolution, * and also init/destroy methods. Bean property accessors have to be public * in any case and are not affected by this setting. * <p>Note that annotation-driven configuration will still access non-public * members as far as they have been annotated. This setting applies to * externalized metadata in this bean definition only. */ public void setNonPublicAccessAllowed(boolean nonPublicAccessAllowed) { this.nonPublicAccessAllowed = nonPublicAccessAllowed; } /** * Return whether to allow access to non-public constructors and methods. */ public boolean isNonPublicAccessAllowed() { return this.nonPublicAccessAllowed; } /** * Specify whether to resolve constructors in lenient mode ({@code true}, * which is the default) or to switch to strict resolution (throwing an exception * in case of ambiguous constructors that all match when converting the arguments, * whereas lenient mode would use the one with the 'closest' type matches). */ public void setLenientConstructorResolution(boolean lenientConstructorResolution) { this.lenientConstructorResolution = lenientConstructorResolution; } /** * Return whether to resolve constructors in lenient mode or in strict mode. */ public boolean isLenientConstructorResolution() { return this.lenientConstructorResolution; } /** * Specify the factory bean to use, if any. * This the name of the bean to call the specified factory method on. * @see #setFactoryMethodName */ @Override public void setFactoryBeanName(String factoryBeanName) { this.factoryBeanName = factoryBeanName; } /** * Return the factory bean name, if any. */ @Override public String getFactoryBeanName() { return this.factoryBeanName; } /** * Specify a factory method, if any. This method will be invoked with * constructor arguments, or with no arguments if none are specified. * The method will be invoked on the specified factory bean, if any, * or otherwise as a static method on the local bean class. * @see #setFactoryBeanName * @see #setBeanClassName */ @Override public void setFactoryMethodName(String factoryMethodName) { this.factoryMethodName = factoryMethodName; } /** * Return a factory method, if any. */ @Override public String getFactoryMethodName() { return this.factoryMethodName; } /** * Specify constructor argument values for this bean. */ public void setConstructorArgumentValues(ConstructorArgumentValues constructorArgumentValues) { this.constructorArgumentValues = (constructorArgumentValues != null ? constructorArgumentValues : new ConstructorArgumentValues()); } /** * Return constructor argument values for this bean (never {@code null}). */ @Override public ConstructorArgumentValues getConstructorArgumentValues() { return this.constructorArgumentValues; } /** * Return if there are constructor argument values defined for this bean. */ public boolean hasConstructorArgumentValues() { return !this.constructorArgumentValues.isEmpty(); } /** * Specify property values for this bean, if any. */ public void setPropertyValues(MutablePropertyValues propertyValues) { this.propertyValues = (propertyValues != null ? propertyValues : new MutablePropertyValues()); } /** * Return property values for this bean (never {@code null}). */ @Override public MutablePropertyValues getPropertyValues() { return this.propertyValues; } /** * Specify method overrides for the bean, if any. */ public void setMethodOverrides(MethodOverrides methodOverrides) { this.methodOverrides = (methodOverrides != null ? methodOverrides : new MethodOverrides()); } /** * Return information about methods to be overridden by the IoC * container. This will be empty if there are no method overrides. * Never returns {@code null}. */ public MethodOverrides getMethodOverrides() { return this.methodOverrides; } /** * Set the name of the initializer method. The default is {@code null} * in which case there is no initializer method. */ public void setInitMethodName(String initMethodName) { this.initMethodName = initMethodName; } /** * Return the name of the initializer method. */ public String getInitMethodName() { return this.initMethodName; } /** * Specify whether or not the configured init method is the default. * Default value is {@code false}. * @see #setInitMethodName */ public void setEnforceInitMethod(boolean enforceInitMethod) { this.enforceInitMethod = enforceInitMethod; } /** * Indicate whether the configured init method is the default. * @see #getInitMethodName() */ public boolean isEnforceInitMethod() { return this.enforceInitMethod; } /** * Set the name of the destroy method. The default is {@code null} * in which case there is no destroy method. */ public void setDestroyMethodName(String destroyMethodName) { this.destroyMethodName = destroyMethodName; } /** * Return the name of the destroy method. */ public String getDestroyMethodName() { return this.destroyMethodName; } /** * Specify whether or not the configured destroy method is the default. * Default value is {@code false}. * @see #setDestroyMethodName */ public void setEnforceDestroyMethod(boolean enforceDestroyMethod) { this.enforceDestroyMethod = enforceDestroyMethod; } /** * Indicate whether the configured destroy method is the default. * @see #getDestroyMethodName */ public boolean isEnforceDestroyMethod() { return this.enforceDestroyMethod; } /** * Set whether this bean definition is 'synthetic', that is, not defined * by the application itself (for example, an infrastructure bean such * as a helper for auto-proxying, created through {@code <aop:config>}). */ public void setSynthetic(boolean synthetic) { this.synthetic = synthetic; } /** * Return whether this bean definition is 'synthetic', that is, * not defined by the application itself. */ public boolean isSynthetic() { return this.synthetic; } /** * Set the role hint for this {@code BeanDefinition}. */ public void setRole(int role) { this.role = role; } /** * Return the role hint for this {@code BeanDefinition}. */ @Override public int getRole() { return this.role; } /** * Set a human-readable description of this bean definition. */ public void setDescription(String description) { this.description = description; } /** * Return a human-readable description of this bean definition. */ @Override public String getDescription() { return this.description; } /** * Set the resource that this bean definition came from * (for the purpose of showing context in case of errors). */ public void setResource(Resource resource) { this.resource = resource; } /** * Return the resource that this bean definition came from. */ public Resource getResource() { return this.resource; } /** * Set a description of the resource that this bean definition * came from (for the purpose of showing context in case of errors). */ public void setResourceDescription(String resourceDescription) { this.resource = new DescriptiveResource(resourceDescription); } /** * Return a description of the resource that this bean definition * came from (for the purpose of showing context in case of errors). */ @Override public String getResourceDescription() { return (this.resource != null ? this.resource.getDescription() : null); } /** * Set the originating (e.g. decorated) BeanDefinition, if any. */ public void setOriginatingBeanDefinition(BeanDefinition originatingBd) { this.resource = new BeanDefinitionResource(originatingBd); } /** * Return the originating BeanDefinition, or {@code null} if none. * Allows for retrieving the decorated bean definition, if any. * <p>Note that this method returns the immediate originator. Iterate through the * originator chain to find the original BeanDefinition as defined by the user. */ @Override public BeanDefinition getOriginatingBeanDefinition() { return (this.resource instanceof BeanDefinitionResource ? ((BeanDefinitionResource) this.resource).getBeanDefinition() : null); } /** * Validate this bean definition. * @throws BeanDefinitionValidationException in case of validation failure */ public void validate() throws BeanDefinitionValidationException { if (!getMethodOverrides().isEmpty() && getFactoryMethodName() != null) { throw new BeanDefinitionValidationException( "Cannot combine static factory method with method overrides: " + "the static factory method must create the instance"); } if (hasBeanClass()) { prepareMethodOverrides(); } } /** * Validate and prepare the method overrides defined for this bean. * Checks for existence of a method with the specified name. * @throws BeanDefinitionValidationException in case of validation failure */ public void prepareMethodOverrides() throws BeanDefinitionValidationException { // Check that lookup methods exists. MethodOverrides methodOverrides = getMethodOverrides(); if (!methodOverrides.isEmpty()) { Set<MethodOverride> overrides = methodOverrides.getOverrides(); synchronized (overrides) { for (MethodOverride mo : overrides) { prepareMethodOverride(mo); } } } } /** * Validate and prepare the given method override. * Checks for existence of a method with the specified name, * marking it as not overloaded if none found. * @param mo the MethodOverride object to validate * @throws BeanDefinitionValidationException in case of validation failure */ protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException { int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName()); if (count == 0) { throw new BeanDefinitionValidationException( "Invalid method override: no method with name '" + mo.getMethodName() + "' on class [" + getBeanClassName() + "]"); } else if (count == 1) { // Mark override as not overloaded, to avoid the overhead of arg type checking. mo.setOverloaded(false); } } /** * Public declaration of Object's {@code clone()} method. * Delegates to {@link #cloneBeanDefinition()}. * @see Object#clone() */ @Override public Object clone() { return cloneBeanDefinition(); } /** * Clone this bean definition. * To be implemented by concrete subclasses. * @return the cloned bean definition object */ public abstract AbstractBeanDefinition cloneBeanDefinition(); @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof AbstractBeanDefinition)) { return false; } AbstractBeanDefinition that = (AbstractBeanDefinition) other; if (!ObjectUtils.nullSafeEquals(getBeanClassName(), that.getBeanClassName())) return false; if (!ObjectUtils.nullSafeEquals(this.scope, that.scope)) return false; if (this.abstractFlag != that.abstractFlag) return false; if (this.lazyInit != that.lazyInit) return false; if (this.autowireMode != that.autowireMode) return false; if (this.dependencyCheck != that.dependencyCheck) return false; if (!Arrays.equals(this.dependsOn, that.dependsOn)) return false; if (this.autowireCandidate != that.autowireCandidate) return false; if (!ObjectUtils.nullSafeEquals(this.qualifiers, that.qualifiers)) return false; if (this.primary != that.primary) return false; if (this.nonPublicAccessAllowed != that.nonPublicAccessAllowed) return false; if (this.lenientConstructorResolution != that.lenientConstructorResolution) return false; if (!ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues)) return false; if (!ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues)) return false; if (!ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides)) return false; if (!ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName)) return false; if (!ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName)) return false; if (!ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName)) return false; if (this.enforceInitMethod != that.enforceInitMethod) return false; if (!ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName)) return false; if (this.enforceDestroyMethod != that.enforceDestroyMethod) return false; if (this.synthetic != that.synthetic) return false; if (this.role != that.role) return false; return super.equals(other); } @Override public int hashCode() { int hashCode = ObjectUtils.nullSafeHashCode(getBeanClassName()); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.scope); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryBeanName); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryMethodName); hashCode = 29 * hashCode + super.hashCode(); return hashCode; } @Override public String toString() { StringBuilder sb = new StringBuilder("class ["); sb.append(getBeanClassName()).append("]"); sb.append("; scope=").append(this.scope); sb.append("; abstract=").append(this.abstractFlag); sb.append("; lazyInit=").append(this.lazyInit); sb.append("; autowireMode=").append(this.autowireMode); sb.append("; dependencyCheck=").append(this.dependencyCheck); sb.append("; autowireCandidate=").append(this.autowireCandidate); sb.append("; primary=").append(this.primary); sb.append("; factoryBeanName=").append(this.factoryBeanName); sb.append("; factoryMethodName=").append(this.factoryMethodName); sb.append("; initMethodName=").append(this.initMethodName); sb.append("; destroyMethodName=").append(this.destroyMethodName); if (this.resource != null) { sb.append("; defined in ").append(this.resource.getDescription()); } return sb.toString(); } }
四:注册解析的BeanDefinition
(1)BeanDefinitionReaderUtils 类
/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.support; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** * Utility methods that are useful for bean definition reader implementations. * Mainly intended for internal use. * * @author Juergen Hoeller * @author Rob Harrop * @since 1.1 * @see PropertiesBeanDefinitionReader * @see org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader */ public class BeanDefinitionReaderUtils { /** * Separator for generated bean names. If a class name or parent name is not * unique, "#1", "#2" etc will be appended, until the name becomes unique. */ public static final String GENERATED_BEAN_NAME_SEPARATOR = BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR; /** * Create a new GenericBeanDefinition for the given parent name and class name, * eagerly loading the bean class if a ClassLoader has been specified. * @param parentName the name of the parent bean, if any * @param className the name of the bean class, if any * @param classLoader the ClassLoader to use for loading bean classes * (can be {@code null} to just register bean classes by name) * @return the bean definition * @throws ClassNotFoundException if the bean class could not be loaded */ public static AbstractBeanDefinition createBeanDefinition( String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setParentName(parentName); if (className != null) { if (classLoader != null) { bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { bd.setBeanClassName(className); } } return bd; } /** * Generate a bean name for the given top-level bean definition, * unique within the given bean factory. * @param beanDefinition the bean definition to generate a bean name for * @param registry the bean factory that the definition is going to be * registered with (to check for existing bean names) * @return the generated bean name * @throws BeanDefinitionStoreException if no unique name can be generated * for the given bean definition * @see #generateBeanName(BeanDefinition, BeanDefinitionRegistry, boolean) */ public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { return generateBeanName(beanDefinition, registry, false); } /** * Generate a bean name for the given bean definition, unique within the * given bean factory. * @param definition the bean definition to generate a bean name for * @param registry the bean factory that the definition is going to be * registered with (to check for existing bean names) * @param isInnerBean whether the given bean definition will be registered * as inner bean or as top-level bean (allowing for special name generation * for inner beans versus top-level beans) * @return the generated bean name * @throws BeanDefinitionStoreException if no unique name can be generated * for the given bean definition */ public static String generateBeanName( BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) throws BeanDefinitionStoreException { String generatedBeanName = definition.getBeanClassName(); if (generatedBeanName == null) { if (definition.getParentName() != null) { generatedBeanName = definition.getParentName() + "$child"; } else if (definition.getFactoryBeanName() != null) { generatedBeanName = definition.getFactoryBeanName() + "$created"; } } if (!StringUtils.hasText(generatedBeanName)) { throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " + "'class' nor 'parent' nor 'factory-bean' - can't generate bean name"); } String id = generatedBeanName; if (isInnerBean) { // Inner bean: generate identity hashcode suffix. id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition); } else { // Top-level bean: use plain class name. // Increase counter until the id is unique. int counter = -1; while (counter == -1 || registry.containsBeanDefinition(id)) { counter++; id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter; } } return id; } /** * Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed */ 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); } } } /** * Register the given bean definition with a generated name, * unique within the given bean factory. * @param definition the bean definition to generate a bean name for * @param registry the bean factory to register with * @return the generated bean name * @throws BeanDefinitionStoreException if no unique name can be generated * for the given bean definition or the definition cannot be registered */ public static String registerWithGeneratedName( AbstractBeanDefinition definition, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String generatedName = generateBeanName(definition, registry, false); registry.registerBeanDefinition(generatedName, definition); return generatedName; } }
(2)DefaultListableBeanFactory 类
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
//--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry interface //--------------------------------------------------------------------- @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) { if (!isAllowBeanDefinitionOverriding()) { 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 { 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); } }
}