【SpringBoot源码分析】-Bean的加载过程 (6)

在该方法中,主要用于处理当前传入的configClass内部的嵌套类、成员类中是否有@Configuration、@Component注解。一般来说@Configuratio
n都是单独使用的一个类。

处理@PropertySource注解

@PropertySource注解用于加载指定的properties配置文件到Spring的Environment中

// 内部实现比较简单,自行debug即可 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { // 判断当前环境对象是否是可配置的 if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } else { logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } 处理@ComponentScan注解

@ComponentScan注解用于指明当前应用将扫描哪些包下的具有@Component注解的类。这个注解必须添加到@Configuration类中

// 根据ComponentScans配置的包路径查找带@Component注解的类 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { // 获取所有带@Component注解的类 for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } }

这里重点分析它是如何查找@ComponentScans注解的,跳过无用的调用链,查看真正开始查找的方法。

// AnnotationConfigUtils.java // 需要注意的是参数:metadata代表从哪里获取,containerClassName表示包含注解(例如@ComponentScans,它本身的值可以包含多个@ComponentScan),annotationClassName是当前要获取的目标注解也就是@ComponentScan static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata, String containerClassName, String annotationClassName) { Set<AnnotationAttributes> result = new LinkedHashSet<>(); // ① // Direct annotation present? addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false)); // ② // Container annotation present? Map<String, Object> container = metadata.getAnnotationAttributes(containerClassName, false); if (container != null && container.containsKey("value")) { for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container.get("value")) { addAttributesIfNotNull(result, containedAttributes); } } // Return merged result return Collections.unmodifiableSet(result); }

提示:
在这个方法内部分了两个操作,第一个是直接获取@ComponentScan这个注解,第二个是获取@ComponentScans注解。这两者是有区别的。

① - 此处为@ComponentScan,称之为直接注解”,即在类上面直接声明的注解。

// StandardAnnotationMetadata.class public Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) { return (this.annotations.length > 0 ? AnnotatedElementUtils.getMergedAnnotationAttributes(getIntrospectedClass(), annotationName, classValuesAsString, this.nestedAnnotationsAsMap) : null); } // AnnotatedElementUtils.class public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element, String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) { AnnotationAttributes attributes = searchWithGetSemantics(element, null, annotationName, new MergedAnnotationAttributesProcessor(classValuesAsString, nestedAnnotationsAsMap)); AnnotationUtils.postProcessAnnotationAttributes(element, attributes, classValuesAsString, nestedAnnotationsAsMap); return attributes; } // 通过一系列的重载方法,最终调用此方法 private static <T> T searchWithGetSemantics(AnnotatedElement element, Set<Class<? extends Annotation>> annotationTypes, @Nullable String annotationName, @Nullable Class<? extends Annotation> containerType, Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) { if (visited.add(element)) { try { // Start searching within locally declared annotations // 获取当前元素声明的所有注解 List<Annotation> declaredAnnotations = Arrays.asList(AnnotationUtils.getDeclaredAnnotations(element)); // 获取这些注解中指定的类型 T result = searchWithGetSemanticsInAnnotations(element, declaredAnnotations, annotationTypes, annotationName, containerType, processor, visited, metaDepth); if (result != null) { return result; } if (element instanceof Class) { // otherwise getAnnotations doesn't return anything new Class<?> superclass = ((Class<?>) element).getSuperclass(); if (superclass != null && superclass != Object.class) { List<Annotation> inheritedAnnotations = new LinkedList<>(); for (Annotation annotation : element.getAnnotations()) { if (!declaredAnnotations.contains(annotation)) { inheritedAnnotations.add(annotation); } } // Continue searching within inherited annotations result = searchWithGetSemanticsInAnnotations(element, inheritedAnnotations, annotationTypes, annotationName, containerType, processor, visited, metaDepth); if (result != null) { return result; } } } } catch (Throwable ex) { AnnotationUtils.handleIntrospectionFailure(element, ex); } } return null; } private static <T> T searchWithGetSemanticsInAnnotations(@Nullable AnnotatedElement element, List<Annotation> annotations, Set<Class<? extends Annotation>> annotationTypes, @Nullable String annotationName, @Nullable Class<? extends Annotation> containerType, Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) { // 遍历所有注解 // Search in annotations for (Annotation annotation : annotations) { // 获取当前注解类型 Class<? extends Annotation> currentAnnotationType = annotation.annotationType(); if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) { // 判断是否处理过、当前注解的名称是否和将要查找的一致、是否默认处理(默认为true,请debug的时候注意传入的参数) if (annotationTypes.contains(currentAnnotationType) || currentAnnotationType.getName().equals(annotationName) || processor.alwaysProcesses()) { // 若匹配,则查找内部的注解属性 T result = processor.process(element, annotation, metaDepth); if (result != null) { if (processor.aggregates() && metaDepth == 0) { processor.getAggregatedResults().add(result); } else { return result; } } } // 如果没有找到 // Repeatable annotations in container? else if (currentAnnotationType == containerType) { for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) { T result = processor.process(element, contained, metaDepth); if (result != null) { // No need to post-process since repeatable annotations within a // container cannot be composed annotations. processor.getAggregatedResults().add(result); } } } } } // Recursively search in meta-annotations for (Annotation annotation : annotations) { Class<? extends Annotation> currentAnnotationType = annotation.annotationType(); if (!AnnotationUtils.hasPlainJavaAnnotationsOnly(currentAnnotationType)) { T result = searchWithGetSemantics(currentAnnotationType, annotationTypes, annotationName, containerType, processor, visited, metaDepth + 1); if (result != null) { processor.postProcess(element, annotation, result); if (processor.aggregates() && metaDepth == 0) { processor.getAggregatedResults().add(result); } else { return result; } } } } return null; } // AnnotatedElementUtils.class内部类AnnotatedElementUtils.class public AnnotationAttributes process(@Nullable AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) { return AnnotationUtils.retrieveAnnotationAttributes(annotatedElement, annotation, this.classValuesAsString, this.nestedAnnotationsAsMap); } // AnnotationUtils.class static AnnotationAttributes retrieveAnnotationAttributes(@Nullable Object annotatedElement, Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap) { Class<? extends Annotation> annotationType = annotation.annotationType(); AnnotationAttributes attributes = new AnnotationAttributes(annotationType); // 遍历注解的方法,获取属性名称和属性值,填充至AnnotationAttributes对象内部(实际上就是个Map) for (Method method : getAttributeMethods(annotationType)) { try { Object attributeValue = method.invoke(annotation); Object defaultValue = method.getDefaultValue(); if (defaultValue != null && ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) { attributeValue = new DefaultValueHolder(defaultValue); } attributes.put(method.getName(), adaptValue(annotatedElement, attributeValue, classValuesAsString, nestedAnnotationsAsMap)); } catch (Throwable ex) { if (ex instanceof InvocationTargetException) { Throwable targetException = ((InvocationTargetException) ex).getTargetException(); rethrowAnnotationConfigurationException(targetException); } throw new IllegalStateException("Could not obtain annotation attribute value for " + method, ex); } } return attributes; }

② - 此处为@ComponentScans,称之为”容器注解”,它可以包含多个@ComponentScan,代码逻辑和获取直接注解@ComponentScan并没有太大差异,可自行debug

看到这里可以得出一个结论:有3种使用注解定义包扫描路径的方法

@SpringBootApplication(scanBasePackages = "com.example")

@ComponentScan(value = {"com.example"})

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfsdy.html