spring context:component-scan
<context:component-scan base-package="com.zhuguang.jack" <!-- 扫描的基本包路径 --> annotation-config="true" <!-- 是否激活属性注入注解 --> name-generator="org.springframework.context.annotation.AnnotationBeanNameGenerator" <!-- Bean的ID策略生成器 --> resource-pattern="**/*.class" <!-- 对资源进行筛选的正则表达式,这边是个大的范畴,具体细分在include-filter与exclude-filter中进行 --> scope-resolver="org.springframework.context.annotation.AnnotationScopeMetadataResolver" <!-- scope解析器 ,与scoped-proxy只能同时配置一个 --> scoped-proxy="no" <!-- scope代理,与scope-resolver只能同时配置一个 --> use-default-filters="false" <!-- 是否使用默认的过滤器,默认值true --> > <!-- 注意:若使用include-filter去定制扫描内容,要在use-default-filters="false"的情况下,不然会“失效”,被默认的过滤机制所覆盖 --> <!-- annotation是对注解进行扫描 ,有这个注解的才会扫描实例化--> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/> <!-- assignable是对类或接口进行扫描 ,实现这个接口的才会扫描实例化--> <context:include-filter type="assignable" expression="com.wjx.betalot.performer.Performer"/> <context:include-filter type="assignable" expression="com.wjx.betalot.performer.impl.Sonnet"/> <context:exclude-filter type="regex" expression=".controller.*"/> <!-- 注意:在use-default-filters="false"的情况下,exclude-filter是针对include-filter里的内容进行排除, 有Controller注解的排除, --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="assignable" expression="com.wjx.betalot.performer.impl.RainPoem"/> <context:exclude-filter type="regex" expression=".service.*"/> </context:component-scan>
public BeanDefinition parse(Element element, ParserContext parserContext) { String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE), ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); //[com.zhuguang.jack] ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element); //扫描器 Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages); registerComponents(parserContext.getReaderContext(), beanDefinitions, element); return null; }
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) { XmlReaderContext readerContext = parserContext.getReaderContext(); //XmlReaderContext@704deff2 boolean useDefaultFilters = true; if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) { useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)); //默认过滤器 } ClassPathBeanDefinitionScanner scanner = createScanner(readerContext, useDefaultFilters); //扫描器 return scanner; }
protected Set<BeanDefinitionHolder> doScan(String... basePackages) { for (String basePackage : basePackages) { Set<BeanDefinition> candidates = findCandidateComponents(basePackage); // [[AnnotationServiceImpl];], [CommonController]; ]], 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); //往bean定义里面设置属性,setLazyInit,setAutowireMode,setDependencyCheck,setInitMethodName,setEnforceInitMethod,setDestroyMethodName,setEnforceDestroyMethod都设置默认值, } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); //往bean定义里面设置属性,是否有Lazy,Primary,DependsOn,Role,Description注解,如果有就设置到bean定义中去。 } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); //把BeanDefinition 变成BeanDefinitionHolder, definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); // beanDefinitions.add(definitionHolder); registerBeanDefinition(definitionHolder, this.registry); //注册到spring容器中, } } } return beanDefinitions; }
public Set<BeanDefinition> findCandidateComponents(String basePackage) { try { String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + "/" + this.resourcePattern; //classpath*:com/zhuguang/jack/**/*.class找到所有的。class文件, Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath); //[file [E:AnnotationServiceImpl.class], file [E:CommonController.class], file [E:CommonMapper.class], file [E:ConsultConfigArea.class], file [E:ConsultContent.class], file [E:MyService.class], file [E:Test2.class], file [E:User.class]] for (Resource resource : resources) { if (isCandidateComponent(metadataReader) && resource.isReadable()) { //没有条件注解,就进来,没有注解的不进来。有@Component注解的才进来, try { MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); //AnnotationMetadata里面封装了这个类的一些基本信息,类里面有哪些方法,方法上面有哪些注解,类上面有哪些注解, if (isCandidateComponent(metadataReader)) {//!(this.isInterface || this.isAbstract) && (this.enclosingClassName == null || this.independentInnerClass); 不是接口不是抽象类就进来,CommonMapper是一个接口不进来, ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); sbd.setSource(resource); if (isCandidateComponent(sbd)) { candidates.add(sbd); } else { } } } } } } return candidates; }
public MetadataReader getMetadataReader(Resource resource) throws IOException { return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader()); } SimpleMetadataReader(Resource resource, ClassLoader classLoader) throws IOException { InputStream is = new BufferedInputStream(resource.getInputStream());//文件流, ClassReader classReader; classReader = new ClassReader(is); AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(classLoader); classReader.accept(visitor, ClassReader.SKIP_DEBUG); this.annotationMetadata = visitor; this.classMetadata = visitor; this.resource = resource; }
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { //metadataReader是类的元数据信息, for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return false; } } for (TypeFilter tf : this.includeFilters) {//interface org.springframework.stereotype.Component,interface javax.inject.Named。有@Component注解的才进来, if (tf.match(metadataReader, this.metadataReaderFactory)) { return isConditionMatch(metadataReader); } } return false; }
public Resource[] getResources(String locationPattern) throws IOException { if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) { if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) { return findPathMatchingResources(locationPattern); } } }
protected Resource[] findPathMatchingResources(String locationPattern) throws IOException { String rootDirPath = determineRootDir(locationPattern); //classpath*:com/zhuguang/jack/ String subPattern = locationPattern.substring(rootDirPath.length()); //**/*.class Resource[] rootDirResources = getResources(rootDirPath); //返回[URL [file:/E:/Code/AAAAA/AAAAA/2019326/2/spring-source-web-master-aop/target/classes/com/zhuguang/jack/]] Set<Resource> result = new LinkedHashSet<Resource>(16); for (Resource rootDirResource : rootDirResources) { rootDirResource = resolveRootDirResource(rootDirResource); //返回[URL [file:/E:/Code/AAAAA/AAAAA/2019326/2/spring-source-web-master-aop/target/classes/com/zhuguang/jack/]] if (isJarResource(rootDirResource)) { result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern)); } else if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) { result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher())); } else { result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern)); } } return result.toArray(new Resource[result.size()]); //[file [E:AnnotationServiceImpl.class], file [E:CommonController.class], file [E:CommonMapper.class], file [E:ConsultConfigArea.class], file [E:ConsultContent.class], file [E:MyService.class], file [E:Test2.class], file [E:User.class]] }
public Resource[] getResources(String locationPattern) throws IOException { else { return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length())); } } } protected Resource[] findAllClassPathResources(String location) throws IOException { Enumeration<URL> resourceUrls = getClassLoader().getResources(path); //AppClassLoader,返回[sun.misc.CompoundEnumeration@b83a9be, java.net.URLClassLoader$3@2609b277] Set<Resource> result = new LinkedHashSet<Resource>(16); while (resourceUrls.hasMoreElements()) { URL url = resourceUrls.nextElement(); result.add(convertClassLoaderURL(url)); } return result.toArray(new Resource[result.size()]); //返回[URL [file:/E:/Code/AAAAA/AAAAA/2019326/2/spring-source-web-master-aop/target/classes/com/zhuguang/jack/]] }
public Enumeration<URL> getResources(String name) throws IOException { @SuppressWarnings("unchecked") Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2]; if (parent != null) { tmp[0] = parent.getResources(name); //ExtClassLoader } else { tmp[0] = getBootstrapResources(name); } tmp[1] = findResources(name); return new CompoundEnumeration<>(tmp); }
private static Enumeration<URL> getBootstrapResources(String name) { final Enumeration<Resource> e = getBootstrapClassPath().getResources(name); //sun.misc.URLClassPath@28d18df5 return new Enumeration<URL> () { public URL nextElement() { return e.nextElement().getURL(); } public boolean hasMoreElements() { return e.hasMoreElements(); } } }