本文主要介绍Spring的component-scan标签,了解spring是如何实现扫描注解进行bean的注册,主要实现实在 NamespaceHandler, NamespaceHandlerSupport 和 BeanDefinitionParser 三个接口中,还须要配置spring.handlers文件,在接下里的源码解析中会详细解析,在本篇博客中将使用ApplicationConntext做为起点,直接从差别开始讲解,若是想了解ApplicationContext 源码的全流程请看上篇博客。html
GItHub:https://github.com/lantaoGitH...java
这里解析解释一下他们之间的关系:node
NamespaceHandlerSupport 是 Abstract 修饰的抽象类 并 实现 NamespaceHandler 接口,继而实现了 NamespaceHandler接口的parser和docreate方法,自定的NamespaceHandler须要继承NamespaceHandlerSupport类并须要实现NamespaceHandler接口的init方法,init方法须要作解析类的注册操做,代码以下:git
package org.springframework.context.config; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; import org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser; import org.springframework.context.annotation.ComponentScanBeanDefinitionParser; /** * {@link org.springframework.beans.factory.xml.NamespaceHandler} * for the '{@code context}' namespace. * * @author Mark Fisher * @author Juergen Hoeller * @since 2.5 */ public class ContextNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser()); registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser()); registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser()); registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser()); registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser()); registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser()); } }/** * Subclasses can call this to register the supplied {@link BeanDefinitionParser} to * handle the specified element. The element name is the local (non-namespace qualified) * name. */ protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) { this.parsers.put(elementName, parser); }BeanDefinitionParser类是解析类的顶层接口,自定义的解析类须要实现BeanDefinitionParser类的Parser方法,解析类的注册就在NameSpaceHandler的init方法中年进行;github
package lantao.scan; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class ScanTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-bean-scan.xml"); } }
xml文件中use-default-filters 属性的默认值为 true,即便用默认的 Filter 进行包扫描,而默认的 Filter 对标有 @Service,@Controller,@Component和@Repository 的注解的类进行扫描 ,若是定位为false的话,就须要进行自定义include-filter。spring
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- use-default-filters 属性的默认值为 true,即便用默认的 Filter 进行包扫描,而默认的 Filter 对标有 @Service,@Controller和@Repository 的注解的类进行扫描 --> <context:component-scan base-package="lantao.scan" use-default-filters="false"> <!-- 只扫描 base-package 的 controller 注解 还有对应的 exclude-filter 标签 排除 ; use-default-filters="false" 和 include-filter 一块儿使用 和 exclude-filter一块儿回抛异常--> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/> </context:component-scan> </beans>
由于这里使用ApplicationContext,ApplicationContext在上篇文章已经进行了源码解读,接下来咱们直接看差别点。express
/** * 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) { //验证xml namespace, BeanDefinitionParserDelegate.BEANS_NAMESPACE_URI 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)) { //对默认标签处理 // 这里只处理 nade namespace 为 http://www.springframework.org/schema/beans 的标签 parseDefaultElement(ele, delegate); } else { //对自定义标签处理 会解析 <context:component-scan base-package="lantao.scan"/> 或者自定义 dubbo delegate.parseCustomElement(ele); } } } } else { //对自定义标签处理 delegate.parseCustomElement(root); } }
主要差别就在 parseDefaultElement(ele, delegate) 和 delegate.parseCustomElement(ele) 方法上,parseDefaultElement方法仅仅会处理node的namespace是:http://www.springframework.org/schema/beans 的标签,其余标签和 自定义标签所有都是经过这个方法来解析的;缓存
@Nullable public BeanDefinition parseCustomElement(Element ele) { return parseCustomElement(ele, null); } @Nullable public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { // 获取node的 NameSpaceURI String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } // 解析自定义标签 须要在 Meta-inf 文件加 增长 spring.handlers 文件 例如:http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler // 根据指定的 NameSpaceURI 获取 NamespaceHandler handler能够参考spring.handlers文件 // abstract NamespaceHandlerSupport 实现了 NamespaceHandler 接口,继而实现了 NamespaceHandler 的两个个方法(parser,docreate),自定义handler 须要实现 NamespaceHandlerSupport 类 // 进行 NamespaceHandler 类的 init 方法的 实现, 主要是作注册 BeanDefinitionParser( registerBeanDefinitionParser ) , 须要自定义解析类 继承 BeanDefinitionParser 类 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)); }
这里代码很简单,只作了一下三件事情:app
1:获取Element的NamespaceUri;ide
2:经过命名空间处理解析器(NamespaceHandlerResolver)的resolver方法进行NameSpaceHandler的处理;
3:经过NameSpaceHandler的Parse方法进行标签解析;
/** * Locate the {@link NamespaceHandler} for the supplied namespace URI * from the configured mappings. * @param namespaceUri the relevant namespace URI * @return the located {@link NamespaceHandler}, or {@code null} if none found */ @Override @Nullable public NamespaceHandler resolve(String namespaceUri) { // 这里获取的是全部注册到 handlerMappings 中的 NamespaceHandler , // 就是 resource/META-INF/spring.handler 中的类 key就是namespaceUri , // 这些类都继承了 NamespaceHandlerSupport 实现了init方法 在init方法中进行 BeanDefinitionParse 的注册 Map<String, Object> handlerMappings = getHandlerMappings(); // 经过 namespaceUri 在 handlerMappings 中获取对应的处理器或者 className 若是是初始化过的就直接返回,反之进行类初始化工做 Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null) { return null; } else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { String className = (String) handlerOrClassName; try { // 实例化 Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); // 判断实例化的类的超类或者超级接口 是不是 NamespaceHandler if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); } NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); // 注册 自定义标签所对应的 解析策略类 解析策略类都继承了 BeanDefinitionParser ,好比 ComponentScanBeanDefinitionParser namespaceHandler.init(); // 放入缓存中 handlerMappings.put(namespaceUri, namespaceHandler); return namespaceHandler; } catch (ClassNotFoundException ex) { throw new FatalBeanException("Could not find NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]", ex); } catch (LinkageError err) { throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]", err); } } }
这里主要作了一件事情,就是获取nameSpaceUri对应的NameSpaceHandler,首先会调动getHandlerMappings方法获取所有的NameSpaceHandler,而后经过namespaceUri获取对应的NameSpaceHandler,若是还未实例化则进行实例化操做执行init方法向parsers注册解析类,反之直接返回;getHandlerMappings方法获取的NameSpaceHandler是解析于resource/META-INF/spring.handler 文件下, key就是namespaceUri,value就是自定义的NameSpaceHandler;
/** * Load the specified NamespaceHandler mappings lazily. */ private Map<String, Object> getHandlerMappings() { Map<String, Object> handlerMappings = this.handlerMappings; if (handlerMappings == null) { synchronized (this) { handlerMappings = this.handlerMappings; if (handlerMappings == null) { if (logger.isTraceEnabled()) { logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]"); } try { // 这里的handlerMappingsLocation指定的地址就是 resources 中的 META-INF/spring.handlers Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); if (logger.isTraceEnabled()) { logger.trace("Loaded NamespaceHandler mappings: " + mappings); } handlerMappings = new ConcurrentHashMap<>(mappings.size()); CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); this.handlerMappings = handlerMappings; } catch (IOException ex) { throw new IllegalStateException( "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex); } } } } return handlerMappings; }
getHandlerMappings就是解析spring.handler文件和执行NameSpaceHandler的init方法并放入缓存的操做,NameSpaceHandler获取到了之后咱们看一下init注册的BeanDefinitionParser的parser方法;
/** * Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is * registered for that {@link Element}. */ @Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { // 在 NamespaceHandlerSupport 中的 parser 集合中获取 BeanDefinitionParser 的实现类 进行 parser BeanDefinitionParser parser = findParserForElement(element, parserContext); return (parser != null ? parser.parse(element, parserContext) : null); }
parse方法作了两件事情:
1:经过定义的标签属性(例如:component-scan)获取对应的BeanDefinitionParser解析类,源码以下:
/** * Locates the {@link BeanDefinitionParser} from the register implementations using * the local name of the supplied {@link Element}. */ @Nullable private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { // 这里判断各类标签的解析策略 获取标签名字 String localName = parserContext.getDelegate().getLocalName(element); // 从 parsers 中获取对应的解析策略类 parsers 是在 NameSpaceHandler 的 init 方法是初始化的; BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } // 返回对应的策略类进行解析 return parser; }
2:开始解析;
@Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { // 获取 basePackage 的 路径 String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE); // 解析给定文本中的${.},将其替换为由{@link #getProperty}解析的相应属性值 就是可使用 ${} 和 properties中的值对应 basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage); //咱们这里在设置 base-package 的值时, 能够经过上面指示的分隔符 ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS 进行多个package的指定. 可使用”,” “;” “\t\n(回车符)”来分割多个包名 String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); // Actually scan for bean definitions and register them. // 下面的代码就是 实际扫描bean定义并注册它们。 // 配置 ClassPathBeanDefinitionScanner ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element); // 扫描 并 注册 Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages); // 处理 annotation-config registerComponents(parserContext.getReaderContext(), beanDefinitions, element); return null; }
parse方法主要作了如下五件事情:
1:获取basePackage的值,就是xml中配置的路径地址;
2:basePackage能够配置多个,使用 ‘,’ ';' 或者回车符 进行分割;
3:初始化ClassPathBeanDefinitionScanner,后边的解析操做有ClassPathBeanDefinitionScanner来完成;
4:扫描并注册bean;
5:处理annotation-config(这个后续会详细讲解,这里就不赘述了)
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) { boolean useDefaultFilters = true; // 设置 use-default-filters 标签 use-default-filters 属性的默认值为 true,即便用默认的 Filter 进行包扫描,而默认的 Filter 对标有 @Service,@Controller和@Repository 的注解的类进行扫描 if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) { useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)); } // Delegate bean definition registration to scanner class. // 将注册Bean的任务委托给ClassPathBeanDefinitionScanner类。初始化 ClassPathBeanDefinitionScanner ,ClassPathBeanDefinitionScanner 是解析conponentScanner 的类 ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters); scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults()); scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns()); // set RESOURCE_PATTERN_ATTRIBUTE 设置 扫描Resource(资源) 路径 默认为 "**/*.class" if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) { scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE)); } try { // set name-generator // 初始化bean 名称生成器 parseBeanNameGenerator(element, scanner); } catch (Exception ex) { parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause()); } try { // 设置bean做用域 parseScope(element, scanner); } catch (Exception ex) { parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause()); } // 设置扫描包含 和 排除的 注解 // 设置过滤器,即用于指定哪些类须要被处理,哪些类须要被忽略 // set INCLUDE_FILTER_ELEMENT and EXCLUDE_FILTER_ELEMENT parseTypeFilters(element, scanner, parserContext); return scanner; }
configureScanner方法主要作了如下五件事:
1:获取并设置use-default-filters,use-default-filters 属性的默认值为 true,即便用默认的 Filter 进行包扫描,而默认的 Filter 对标有 @Service,@Controller和@Repository 的注解的类进行扫描,若是设置为false,则须要自行对include-filter添加;
2:初始化ClassPathBeanDefinitionScanner,若是use-default-filters为true则对include-filter进行add操做;
3:初始化bean 名称生成器;
4:设置bean做用域;
5:设置扫描包含 和 排除的 注解,include-filter和exclude-filter;
上述代码就不展示了,git上代码有对应的注释;
/** * 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<>(); // 循环扫描 for (String basePackage : basePackages) { // 获取指定包下全部 BeanDefinition Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { // 获取一个ScopeMetadata对象,默认为AnnotationScopeMetadataResolver // 若是目标类未被@Scope注解,则返回一个默认的ScopeMetadata ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); // 使用bean名称生成器生成bean名称,默认生成器为AnnotationBeanNameGenerator // 首先是以注解的value为bean名称,若是注解的value没有值,则使用默认的名称 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { // 处理定义在目标类上的注解,包括@Lazy, @Primary, @DependsOn, @Role, @Description // 这里会检查和 设置 AnnotatedBeanDefinition 的 @Lazy(懒加载) @Primary(主要,https://www.cnblogs.com/liaojie970/p/7885106.html) @DependsOn(须要依赖但不须要持有) 注解 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } // 检查beanName是否已经存在 BeanDefinitionRegistry 中存在。 if (checkCandidate(beanName, candidate)) { //beanName 还没使用过 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); // 若是有必要,则建立做用域代理 // 若是建立了代理,则返回表示代理对象的BeanDefinitionHolder definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); // 注册Bean registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
看如下在doScan方法中都作了什么:
1:获取指定包下(指定的basePackage)全部 BeanDefinition;
2:获取一个ScopeMetadata对象,默认为AnnotationScopeMetadataResolver,若是目标类未被@Scope注解,则返回一个默认的ScopeMetadata;
3:使用bean名称生成器生成bean名称,默认生成器为AnnotationBeanNameGenerator,若是注解上的value值是null,则须要生成;
4:设置AutowireCandidate autowire-candidate="false" 表示该对象不参与自动注入,借鉴:https://blog.csdn.net/shangbo...
5:处理定义在目标类上的注解,包括@Lazy, @Primary, @DependsOn, @Role, @Description,这里会检查和设置 AnnotatedBeanDefinition 的 @Lazy(懒加载) @Primary(主要,https://www.cnblogs.com/liaoj... @DependsOn(须要依赖但不须要持有) 注解;
6:检查beanName是否已经存在 beanDefinitionMap 中存在;
7:若是设置了scopedProxyMode,则须要建立代理类和注册代理类;
8:调用registerBeanDefinition注册bean,就是put到beanDefinitionMap中;
private Set<BeanDefinition> scanCandidateComponents(String basePackage) { Set<BeanDefinition> candidates = new LinkedHashSet<>(); try { // ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX = "classpath*:"; // 经过观察resolveBasePackage()方法的实现, 咱们能够在设置basePackage时, 使用形如${}的占位符, Spring会在这里进行替换 // this.resourcePattern 默认为 "**/*.class" resourcePattern 能够再xml中配置 String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; // 使用上面拼接出的形如 "classpath*:xx/yyy/zzz/**/*.class", 将其检索为Spring内置的Resource对象(这样就统一化了资源的差别) // 使用ResourcePatternResolver的getResources方法获取 路径下所有 好比:classpath*:lantao/scan/**/*.class Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); boolean traceEnabled = logger.isTraceEnabled(); boolean debugEnabled = logger.isDebugEnabled(); for (Resource resource : resources) { if (traceEnabled) { logger.trace("Scanning " + resource); } // file是否可读 if (resource.isReadable()) { try { // 获取元数据 元数据就是用来定义数据的数据 就是定义 class 的 属性 MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); // 根据锅炉器来判断是否符合要求 作 includeFilters excludeFilters 的判断 if (isCandidateComponent(metadataReader)) { // 实例化 ScannedGenericBeanDefinition 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; }
这里主要就是作了经过ResourcePatternResolver的getResource获取指定路径的资源文件,再经过资源文件Resource获取MetadataReader (元数据就是用来定义数据的数据 就是定义 class 的 属性),接下来经过isCandidateComponent方法来作核心处理,由于经过路径获取的资源是所有的,不是想要的,经过isCandidateComponent方法来作 ncludeFilters excludeFilters 的判断,再经过isCandidateComponent(sbd)判断BeanDefinition必须是一个实现类,不能够是接口等;
/** * Determine whether the given class does not match any exclude filter * and does match at least one include filter. * @param metadataReader the ASM ClassReader for the class * @return whether the class qualifies as a candidate component */ protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { // 判断 excludeFilters 的 TypeFilter for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, getMetadataReaderFactory())) { return false; } } // 判断逻辑 includeFilters 中的 TypeFilter 默认包含的filter有 @components 和 引用他的 @service @controller @Repository for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, getMetadataReaderFactory())) { // 判断 @Conditional , @Conditional是Spring4新提供的注解,它的做用是按照必定的条件进行判断,知足条件给容器注册bean。 还有 @ConditionalOnXX 等注解 return isConditionMatch(metadataReader); } } return false; }
/** * Determine whether the given bean definition qualifies as candidate. * <p>The default implementation checks whether the class is not an interface * and not dependent on an enclosing class. * <p>Can be overridden in subclasses. * @param beanDefinition the bean definition to check * @return whether the bean definition qualifies as a candidate component */ protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { AnnotationMetadata metadata = beanDefinition.getMetadata(); // metadata.isIndependent() 是独立的 & // metadata.isConcrete() 是不是接口或者是抽象类 或 // 必须是抽象类 和 有@lookup 注解 return (metadata.isIndependent() && (metadata.isConcrete() || (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName())))); }
到这里就已经讲完了Component-scan扫描注入的源码,这里涉及代理和annotation-config没有作详细的讲解,会在后续的文章中作,码字不易,转发请注明出处。