Spring源码阅读之Bean加载(annotation )2

来源:互联网 发布:哪里可以恢复手机数据 编辑:程序博客网 时间:2024/05/20 20:43

继续上面的话题,在前面简要的说明了XmlBeanFactory加载Bean的整体流程,主要了解了容器对Xml配置文件的Bean的加载过程,对Xml中bean的解析是DefaultNamespace的,也就是对上上面有说到的方法:

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);}}

其中parseDefaultElement(ele, delegate);就是xml文件标签的解析,DefaultNamespace下解析了四种标签,

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)) {// recursedoRegisterBeanDefinitions(ele);}}

此方法进入解析BeanDefinitionParserDelegate类,进行xml标签的解析处理以及BeanDefinition的生成,上篇文章也有讲到。默认解析并没有使用paraser类。

DefaultNamespace的解析标签有import ,alias,beans和bean,其中beans是递归调用,再次进入方法解析bean等。流程大体一致。这是非注解形式的,那么注解形式的bean又是如何加载的呢?

Xml和注解Bean的解析是从上面parseBeanDefinitions进行分别处理的, delegate.parseCustomElement(ele);就是处理了不是DefaultNamespace的情况,注解就属于其中一类。进入delegate对象,查看方法如下:

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));}

这里的NamespaceHandler 的实现类有NamespaceHandlerSupport等,NamespaceHandlerSupport有子类

public class AopNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {// In 2.0 XSD as well as in 2.1 XSD.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());// Only in 2.0 XSD: moved to context namespace as of 2.1registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());}}

可以看到AopNamespaceHandler注册了“aspectj-autoproxy"代理的解析器AspectJAutoProxyBeanDefinitionParser。

进入NamespaceHandlerSupport的parse方法:

public BeanDefinition parse(Element element, ParserContext parserContext) {return findParserForElement(element, parserContext).parse(element, parserContext);}

可以看到,这里根据localName获取BeanDefinitionParser解析器。对应<context:component-scan 的解析器为ComponentScanBeanDefinitionParser。

当配置文件中配置了

<context:component-scan base-package="com.**" />

后,Spring会扫描指定包下有使用了注解的类,进行BeanDefinition的生成。xml配置文件中的所有配置都可以认为是一个bean,<context也不例外,当从Document解析Element元素节点,解析到对应于<context :componet-scan时,会获取对应ComponentScanBeanDefinitionParser,调用其parse方法,获取base-package属性,扫描所有类,生成BeanDefiitionHolder&注册。

如下:

@Overridepublic BeanDefinition parse(Element element, ParserContext parserContext) {
<span style="white-space:pre"></span>//获取<span style="font-family: Arial; font-size: 14px; line-height: 26px; white-space: pre;"><context :componet-scan base-package="**"/>下</span><span style="font-family: Arial;">base-package</span>内容String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE),ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);// Actually scan for bean definitions and register them.ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);registerComponents(parserContext.getReaderContext(), beanDefinitions, element);return null;}
获取scanner的方法

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {XmlReaderContext readerContext = parserContext.getReaderContext();boolean useDefaultFilters = true;if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));}// Delegate bean definition registration to scanner class.
<span style="white-space:pre"></span>/*生成<span style="font-family: Arial;">ClassPathBeanDefinitionScanner</span>对象,并进行一系列设置*/
ClassPathBeanDefinitionScanner scanner = createScanner(readerContext, useDefaultFilters);scanner.setResourceLoader(readerContext.getResourceLoader());scanner.setEnvironment(parserContext.getDelegate().getEnvironment());scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));}<pre name="code" class="java">try {<pre name="code" class="java" style="font-size: 14px; line-height: 26px;"><span style="white-space:pre"></span>//如果有name-generator属性,则生成BeanNameGenerator,并赋值到scanner对象
<span style="white-space:pre"></span>//<span></span> Set the BeanNameGenerator to use for detected bean classes.
parseBeanNameGenerator(element, scanner);}catch (Exception ex) {readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());}try {// Register ScopeMetadataResolver if class name provided.Scope属性元数据解析工具parseScope(element, scanner);}catch (Exception ex) {readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());}parseTypeFilters(element, scanner, readerContext, parserContext);return scanner;}

</pre><pre class="java" name="code">protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters);}
protected void parseBeanNameGenerator(Element element, ClassPathBeanDefinitionScanner scanner) {if (element.hasAttribute(NAME_GENERATOR_ATTRIBUTE)) {
<span style="white-space:pre"></span>//instantiateUserDefinedStrategy方法下:classLoader.loadClass(className).newInstance()加载<span style="font-family: Arial;">BeanNameGenerator</span>BeanNameGenerator beanNameGenerator = (BeanNameGenerator) instantiateUserDefinedStrategy(element.getAttribute(NAME_GENERATOR_ATTRIBUTE), BeanNameGenerator.class,scanner.getResourceLoader().getClassLoader());scanner.setBeanNameGenerator(beanNameGenerator);}}

protected void parseScope(Element element, ClassPathBeanDefinitionScanner scanner) {// Register ScopeMetadataResolver if class name provided.if (element.hasAttribute(SCOPE_RESOLVER_ATTRIBUTE)) {if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {throw new IllegalArgumentException("Cannot define both 'scope-resolver' and 'scoped-proxy' on <component-scan> tag");}ScopeMetadataResolver scopeMetadataResolver = (ScopeMetadataResolver) instantiateUserDefinedStrategy(element.getAttribute(SCOPE_RESOLVER_ATTRIBUTE), ScopeMetadataResolver.class,scanner.getResourceLoader().getClassLoader());scanner.setScopeMetadataResolver(scopeMetadataResolver);}if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {String mode = element.getAttribute(SCOPED_PROXY_ATTRIBUTE);if ("targetClass".equals(mode)) {scanner.setScopedProxyMode(ScopedProxyMode.TARGET_CLASS);}else if ("interfaces".equals(mode)) {scanner.setScopedProxyMode(ScopedProxyMode.INTERFACES);}else if ("no".equals(mode)) {scanner.setScopedProxyMode(ScopedProxyMode.NO);}else {throw new IllegalArgumentException("scoped-proxy only supports 'no', 'interfaces' and 'targetClass'");}}}

protected void parseTypeFilters(Element element, ClassPathBeanDefinitionScanner scanner, XmlReaderContext readerContext, ParserContext parserContext) {// Parse exclude and include filter elements.ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();NodeList nodeList = element.getChildNodes();for (int i = 0; i < nodeList.getLength(); i++) {Node node = nodeList.item(i);if (node.getNodeType() == Node.ELEMENT_NODE) {String localName = parserContext.getDelegate().getLocalName(node);try {if (INCLUDE_FILTER_ELEMENT.equals(localName)) {
<span style="white-space:pre"></span>//<span style="white-space:pre"></span>根据子节点获取TypeFilterTypeFilter typeFilter = createTypeFilter((Element) node, classLoader);scanner.addIncludeFilter(typeFilter);}else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {TypeFilter typeFilter = createTypeFilter((Element) node, classLoader);scanner.addExcludeFilter(typeFilter);}}catch (Exception ex) {readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());}}}}
@SuppressWarnings("unchecked")protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader) {String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);try {if ("annotation".equals(filterType)) {return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));}else if ("assignable".equals(filterType)) {return new AssignableTypeFilter(classLoader.loadClass(expression));}else if ("aspectj".equals(filterType)) {return new AspectJTypeFilter(expression, classLoader);}else if ("regex".equals(filterType)) {return new RegexPatternTypeFilter(Pattern.compile(expression));}else if ("custom".equals(filterType)) {Class<?> filterClass = classLoader.loadClass(expression);if (!TypeFilter.class.isAssignableFrom(filterClass)) {throw new IllegalArgumentException("Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);}return (TypeFilter) BeanUtils.instantiateClass(filterClass);}else {throw new IllegalArgumentException("Unsupported filter type: " + filterType);}}catch (ClassNotFoundException ex) {throw new FatalBeanException("Type filter class not found: " + expression, ex);}}

TypeFilter,顾名思义,就是一个类型过滤器,用来扫描类的时候i,决定一个类是否被过滤,比如AnnotationTypeFilter,通过获得的注解来匹配类型,看下类的注释:

/** * A simple filter which matches classes with a given annotation, * checking inherited annotations as well. * * <p>The matching logic mirrors that of {@code Class.isAnnotationPresent()}. * * @author Mark Fisher * @author Ramnivas Laddad * @author Juergen Hoeller * @since 2.5 */public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter {private final Class<? extends Annotation> annotationType;private final boolean considerMetaAnnotations;
***省略}
到这里,我们看到了scanner扫描器的生成过程,以及其包含的内容,比如一些TypeFilter匹配器等。

重点到了:

Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
扫描指定的packages。
/** * Perform a scan within the specified base packages, * returning the registered bean definitions. * <p>This method does <i>not</i> register an annotation config processor * but rather leaves this up to the caller. * @param basePackages the packages to check for annotated classes * @return set of beans registered if any for tooling registration purposes (never {@code null}) */protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();for (String basePackage : basePackages) {Set<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}
获取候选BeanDefinition:

/** * Scan the class path for candidate components. * @param basePackage the package to check for annotated classes * @return a corresponding Set of autodetected bean definitions */public Set<BeanDefinition> findCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();try {//   解析为 classpath*: thePackage /**/*.classString packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + "/" + this.resourcePattern;Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);boolean traceEnabled = logger.isTraceEnabled();boolean debugEnabled = logger.isDebugEnabled();for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning " + resource);}if (resource.isReadable()) {try {MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);if (isCandidateComponent(metadataReader)) {ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);sbd.setResource(resource);sbd.setSource(resource);if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class: " + resource);}candidates.add(sbd);}else {if (debugEnabled) {logger.debug("Ignored because not a concrete top-level class: " + resource);}}}else {if (traceEnabled) {logger.trace("Ignored because not matching any filter: " + resource);}}}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);}}else {if (traceEnabled) {logger.trace("Ignored because not readable: " + resource);}}}}catch (IOException ex) {throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);}return candidates;}
方法首先处理package字符串,替换为classpath*:thePackage/**/*.class形式。然后调用PathMatchingResourcePatternResolver的getResources方法
如下:

@Overridepublic Resource[] getResources(String locationPattern) throws IOException {Assert.notNull(locationPattern, "Location pattern must not be null");if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {// a class path resource (multiple resources for same name possible)if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {// a class path resource patternreturn findPathMatchingResources(locationPattern);}else {// all class path resources with the given namereturn findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));}}else {// Only look for a pattern after a prefix here// (to not get fooled by a pattern symbol in a strange prefix).int prefixEnd = locationPattern.indexOf(":") + 1;if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {// a file patternreturn findPathMatchingResources(locationPattern);}else {// a single resource with the given namereturn new Resource[] {getResourceLoader().getResource(locationPattern)};}}}

/** * Find all resources that match the given location pattern via the * Ant-style PathMatcher. Supports resources in jar files and zip files * and in the file system. * @param locationPattern the location pattern to match * @return the result as Resource array * @throws IOException in case of I/O errors * @see #doFindPathMatchingJarResources * @see #doFindPathMatchingFileResources * @see org.springframework.util.PathMatcher */protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {String rootDirPath = determineRootDir(locationPattern);String subPattern = locationPattern.substring(rootDirPath.length());Resource[] rootDirResources = getResources(rootDirPath);Set<Resource> result = new LinkedHashSet<Resource>(16);for (Resource rootDirResource : rootDirResources) {rootDirResource = resolveRootDirResource(rootDirResource);if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));}else if (isJarResource(rootDirResource)) {result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));}else {result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));}}if (logger.isDebugEnabled()) {logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);}return result.toArray(new Resource[result.size()]);}
获取根目录下所有Resource

@Overridepublic Resource[] getResources(String locationPattern) throws IOException {Assert.notNull(locationPattern, "Location pattern must not be null");if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {//"classpath*:"// a class path resource (multiple resources for same name possible)if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {// a class path resource patternreturn findPathMatchingResources(locationPattern);}else {// all class path resources with the given namereturn findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));}}else {// Only look for a pattern after a prefix here// (to not get fooled by a pattern symbol in a strange prefix).int prefixEnd = locationPattern.indexOf(":") + 1;if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {// a file patternreturn findPathMatchingResources(locationPattern);}else {// a single resource with the given namereturn new Resource[] {getResourceLoader().getResource(locationPattern)};}}}
方法是不是又回来了?是的,这里递归调用了getResources,还是直接看获取的方法吧,
protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)throws IOException {File rootDir;try {rootDir = rootDirResource.getFile().getAbsoluteFile();}catch (IOException ex) {if (logger.isWarnEnabled()) {logger.warn("Cannot search for matching files underneath " + rootDirResource +" because it does not correspond to a directory in the file system", ex);}return Collections.emptySet();}return doFindMatchingFileSystemResources(rootDir, subPattern);}

/** * Find all resources in the file system that match the given location pattern * via the Ant-style PathMatcher. * @param rootDir the root directory in the file system * @param subPattern the sub pattern to match (below the root directory) * @return a mutable Set of matching Resource instances * @throws IOException in case of I/O errors * @see #retrieveMatchingFiles * @see org.springframework.util.PathMatcher */protected Set<Resource> doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException {if (logger.isDebugEnabled()) {logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]");}Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);Set<Resource> result = new LinkedHashSet<Resource>(matchingFiles.size());for (File file : matchingFiles) {result.add(new FileSystemResource(file));}return result;}


找到这里,文件的加载差不多说完了,总结一下,比如说scan路径为"com/pack/",则生成的路径为“classpath*:com/pack/**/*.calss",递归获取Resourcce,先处理为"classpath*:com/pack/",调用findAllClassPathResources方法,

protected Resource[] findAllClassPathResources(String location) throws IOException {String path = location;if (path.startsWith("/")) {path = path.substring(1);}Set<Resource> result = doFindAllClassPathResources(path);return result.toArray(new Resource[result.size()]);}
//Find all class location resources with the given path via the ClassLoader
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {Set<Resource> result = new LinkedHashSet<Resource>(16);ClassLoader cl = getClassLoader();Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));while (resourceUrls.hasMoreElements()) {URL url = resourceUrls.nextElement();result.add(convertClassLoaderURL(url));}if ("".equals(path)) {// The above result is likely to be incomplete, i.e. only containing file system references.// We need to have pointers to each of the jar files on the classpath as well...addAllClassLoaderJarRoots(cl, result);}return result;}

使用ClassLoader获取目录下的资源,若目录下还有子目录,则获取子目录资源。

所有的Resource(rul)获取之后,我们回到findCandidateComponents方法:

public Set<BeanDefinition> findCandidateComponents(String basePackage) {  Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();  try {   String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +     resolveBasePackage(basePackage) + "/" + this.resourcePattern;   Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);   boolean traceEnabled = logger.isTraceEnabled();   boolean debugEnabled = logger.isDebugEnabled();   for (Resource resource : resources) {    if (traceEnabled) {     logger.trace("Scanning " + resource);    }    if (resource.isReadable()) {     try {      MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);      if (isCandidateComponent(metadataReader)) {       ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);       sbd.setResource(resource);       sbd.setSource(resource);       if (isCandidateComponent(sbd)) {        if (debugEnabled) {         logger.debug("Identified candidate component class: " + resource);        }        candidates.add(sbd);       }       else {        if (debugEnabled) {         logger.debug("Ignored because not a concrete top-level class: " + resource);        }       }      }      else {       if (traceEnabled) {        logger.trace("Ignored because not matching any filter: " + resource);       }      }     }     catch (Throwable ex) {      throw new BeanDefinitionStoreException(        "Failed to read candidate component class: " + resource, ex);     }    }    else {     if (traceEnabled) {      logger.trace("Ignored because not readable: " + resource);     }    }   }  }  catch (IOException ex) {   throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);  }  return candidates; }

对获取的Resource进行遍历,调用isCandidateComponent(metadataReader)来进行过滤,

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {for (TypeFilter tf : this.excludeFilters) {if (tf.match(metadataReader, this.metadataReaderFactory)) {return false;}}for (TypeFilter tf : this.includeFilters) {if (tf.match(metadataReader, this.metadataReaderFactory)) {return isConditionMatch(metadataReader);}}return false;}


类型匹配过滤,比如说类是否存在注解等。进行一系列操作后回到调用者doScan:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();for (String basePackage : basePackages) {Set<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}
得到BeanDefinition并返回,外层流程注册到容器。


















0 0
原创粉丝点击