当前位置:   article > 正文

Spring-包扫描_spring怎么扫描包

spring怎么扫描包

 一、doScan包扫描

V1.0 doScan
流程图

包扫描

1、根据配置的包扫名路径构建出Beandefinition

2、循环构建出的BeanDefinition集合

3、获取ScopeMetadata元数据读取器

4、对beandefinition进行赋值

5、返回所有的beandefinition

  1. protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
  2. Assert.notEmpty(basePackages, "At least one base package must be specified");
  3. Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
  4. for (String basePackage : basePackages) {
  5. //获取路径下的所有BeanDefinition
  6. //具体看代码V1.1
  7. Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
  8. for (BeanDefinition candidate : candidates) {
  9. //设置bean的作用范围 默认 singleton
  10. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
  11. candidate.setScope(scopeMetadata.getScopeName());
  12. //对beanDefinition设置bean的名字
  13. String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
  14. //对beanDefinition设置默认值
  15. if (candidate instanceof AbstractBeanDefinition) {
  16. postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
  17. }
  18. if (candidate instanceof AnnotatedBeanDefinition) {
  19. // 解析@Lazy、@Primary、@DependsOn、@Role、@Description
  20. //并设置给当前beanDefinition
  21. AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
  22. }
  23. // 检查Spring容器中是否已经存在该beanName
  24. //见的代码V1.7
  25. if (checkCandidate(beanName, candidate)) {
  26. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
  27. definitionHolder =
  28. AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  29. beanDefinitions.add(definitionHolder);
  30. // 注册,将beanName作为key beanDefinition作为value存入beanDefinitionMap中
  31. registerBeanDefinition(definitionHolder, this.registry);
  32. }
  33. }
  34. }
  35. return beanDefinitions;
  36. }
V1.1 isCandidateComponent

判断当前类是否需要当作bean进行处理

  1. public Set<BeanDefinition> findCandidateComponents(String basePackage) {
  2. //componentsIndex 对应META-INF下的spring.components文件,里面的内容全包名类名作为key,注解名作为value
  3. //加入该文件后,就会走这边的逻辑,只扫描配置好的类,可以减少扫描时间
  4. if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
  5. return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
  6. }
  7. else {
  8. return scanCandidateComponents(basePackage);
  9. }
  10. }
  11. ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  12. private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
  13. Set<BeanDefinition> candidates = new LinkedHashSet<>();
  14. try {
  15. // 获取basePackage下所有的文件资源 CLASSPATH_ALL_URL_PREFIX = "classpath*:"
  16. // DEFAULT_RESOURCE_PATTERN = "**/*.class";
  17. String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
  18. resolveBasePackage(basePackage) + '/' + this.resourcePattern;
  19. //获取包路径下的所有的.class文件
  20. Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
  21. boolean traceEnabled = logger.isTraceEnabled();
  22. boolean debugEnabled = logger.isDebugEnabled();
  23. //遍历每一个文件
  24. for (Resource resource : resources) {
  25. if (traceEnabled) {
  26. logger.trace("Scanning " + resource);
  27. }
  28. if (resource.isReadable()) {
  29. try {
  30. //获取 元数据读取器,可以读取类名、类中的方法、类上的注解等元素据
  31. MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
  32. // excludeFilters、includeFilters判断
  33. // 代码V1.2
  34. if (isCandidateComponent(metadataReader)) { // @Component--
  35. >includeFilters判断
  36. //创建BeanDefinition,并将className赋值给BeanClass
  37. ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
  38. sbd.setSource(resource);
  39. if (isCandidateComponent(sbd)) {
  40. if (debugEnabled) {
  41. logger.debug("Identified candidate component class: " + resource);
  42. }
  43. candidates.add(sbd);
  44. }
  45. else {
  46. if (debugEnabled) {
  47. logger.debug("Ignored because not a concrete top-level class: " + resource);
  48. }
  49. }
  50. }
  51. else {
  52. if (traceEnabled) {
  53. logger.trace("Ignored because not matching any filter: " + resource);
  54. }
  55. }
  56. }
  57. catch (Throwable ex) {
  58. throw new BeanDefinitionStoreException(
  59. "Failed to read candidate component class: " + resource, ex);
  60. }
  61. }
  62. else {
  63. if (traceEnabled) {
  64. logger.trace("Ignored because not readable: " + resource);
  65. }
  66. }
  67. }
  68. }
  69. catch (IOException ex) {
  70. throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
  71. }
  72. return candidates;
  73. }
V1.2 isCandidateComponent

  1. protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
  2. for (TypeFilter tf : this.excludeFilters) {
  3. if (tf.match(metadataReader, getMetadataReaderFactory())) {
  4. return false;
  5. }
  6. }
  7. // 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional
  8. //spring启动的时候会自动将@Component注解加入includeFilters中
  9. // 具体看代码 V1.3
  10. for (TypeFilter tf : this.includeFilters) {
  11. if (tf.match(metadataReader, getMetadataReaderFactory())) {
  12. //当类满足Component注解或其他设定为需要加载Bean的注解
  13. // 仍需要判断是否满足条件@Conditional注解中包含的条件
  14. return isConditionMatch(metadataReader);
  15. }
  16. }
  17. return false;
  18. }

V1.3 registerDefaultFilters

spring在启动的时候就会往includeFilters中加入component注解

  1. protected void registerDefaultFilters() {
  2. // 注册@Component对应的AnnotationTypeFilter
  3. this.includeFilters.add(new AnnotationTypeFilter(Component.class));
  4. ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
  5. try {
  6. this.includeFilters.add(new AnnotationTypeFilter(
  7. ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
  8. logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
  9. }
  10. catch (ClassNotFoundException ex) {
  11. // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
  12. }
  13. try {
  14. this.includeFilters.add(new AnnotationTypeFilter(
  15. ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
  16. logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
  17. }
  18. catch (ClassNotFoundException ex) {
  19. // JSR-330 API not available - simply skip.
  20. }
  21. }
V1.4 ScannedGenericBeanDefinition

对扫描到的BeanDefinition进行赋值,但是此时只是将className赋值到BeanDefinition中,因为还没有创建该类

  1. public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
  2. Assert.notNull(metadataReader, "MetadataReader must not be null");
  3. this.metadata = metadataReader.getAnnotationMetadata();
  4. // 这里只是把className设置到BeanDefinition中
  5. setBeanClassName(this.metadata.getClassName());
  6. setResource(metadataReader.getResource());
  7. }
  8. ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  9. @Override
  10. public void setBeanClassName(@Nullable String beanClassName) {
  11. this.beanClass = beanClassName;
  12. }
V1.5 isCandidateComponent

二次判断类是否可独立实例化对象,内部类或者接口,抽象类都会对应生成一个.class文件,但是这些文件部分是不能够实例化的,不可以生成bean,所以在生成BeanDefinition之前需要进行过滤判断

  1. /**
  2. *确定给定的bean定义是否符合候选条件。
  3. *默认实现检查类是否不是接口并且不依赖于封闭类且可以在子类中重写
  4. *(即
  5. * 1、是否是顶级类或者静态内部类等独立类,
  6. * 2、不是接口并且不是抽象类,
  7. * 3、如果是抽象类,含有至少一个方法实现Lookup注解)
  8. *
  9. */
  10. protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
  11. AnnotationMetadata metadata = beanDefinition.getMetadata();
  12. return (metadata.isIndependent() && (metadata.isConcrete() ||
  13. (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
  14. }
  15. ↓↓↓↓↓↓↓↓↓↓
  16. default boolean isConcrete() {
  17. //判断不是接口并且不是抽象类
  18. return !(isInterface() || isAbstract());
  19. }

V1.6 generateBeanName

获取bean的名字

  1. @Override
  2. public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
  3. if (definition instanceof AnnotatedBeanDefinition) {
  4. // 获取注解所指定的beanName
  5. String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
  6. if (StringUtils.hasText(beanName)) {
  7. // Explicit bean name found.
  8. return beanName;
  9. }
  10. }
  11. // 如果注解中没有指定bean的名称,则采用默认名称
  12. return buildDefaultBeanName(definition, registry);
  13. }
  14. ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  15. protected String buildDefaultBeanName(BeanDefinition definition) {
  16. String beanClassName = definition.getBeanClassName();
  17. Assert.state(beanClassName != null, "No bean class name set");
  18. //获取sortName
  19. //如果beanClassName长度小于0返回空
  20. //如果beanClassName的第一个第二个字母都是大写,则返回beanClassName
  21. //否则将beanClassName的第一个字母设为小写后,返回
  22. String shortClassName = ClassUtils.getShortName(beanClassName);
  23. return Introspector.decapitalize(shortClassName);
  24. }

V1.7 checkCandidate

  1. protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
  2. //当前bean的名字并没有被注册过,返回true
  3. if (!this.registry.containsBeanDefinition(beanName)) {
  4. return true;
  5. }
  6. BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
  7. BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
  8. if (originatingDef != null) {
  9. existingDef = originatingDef;
  10. }
  11. // 是否兼容,如果兼容返回false表示不会重新注册到Spring容器中,如果不冲突则会抛异常。
  12. if (isCompatible(beanDefinition, existingDef)) {
  13. return false;
  14. }
  15. //大多数情况下,名字重复会直接抛出异常
  16. throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
  17. "' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
  18. "non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
  19. }
  20. ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  21. protected boolean isCompatible(BeanDefinition newDefinition, BeanDefinition existingDefinition) {
  22. //判断beanDefinition是否是统一类型,如果是,代表多次扫描统一相同的bean,而非不同的bean使用相同的名称
  23. //可兼容,但是跳过本次处理
  24. return (!(existingDefinition instanceof ScannedGenericBeanDefinition) || // explicitly registered overriding bean
  25. (newDefinition.getSource() != null && newDefinition.getSource().equals(existingDefinition.getSource())) || // scanned same file twice
  26. newDefinition.equals(existingDefinition)); // scanned equivalent class twice
  27. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/942607
推荐阅读
相关标签
  

闽ICP备14008679号