看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead

代码过宽,可以shift + 鼠标滚轮 左右滑动查看

这篇文章主要跟踪spring配置文件中component-scan标签,查看它是怎样被解析扫描生成对应的beanDefinition。

在applicationContext.xml中做以下配置:

  1. <!-- 启动组件扫描,排除@Controller组件,该组件由SpringMVC配置文件扫描 -->
  2. <context:component-scan base-package="cn.mrdear">
  3. <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
  4. <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController" />
  5. </context:component-scan>

以DefaultBeanDefinitionDocumentReader类中的parseBeanDefinitions方法作为开始,向下跟踪。

  1. /**
  2. * Parse the elements at the root level in the document:
  3. * "import", "alias", "bean".
  4. *
  5. * 解析在文档中根层级的元素:"import", "alias", "bean".
  6. */
  7. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
  8. //默认名称空间是"http://www.springframework.org/schema/beans"
  9. //进入条件
  10. if (delegate.isDefaultNamespace(root)) {
  11. //获取根元素下的子Node,注意,Node不一定是子标签,可能是回车,可能是注释
  12. NodeList nl = root.getChildNodes();
  13. for (int i = 0; i < nl.getLength(); i++) {
  14. Node node = nl.item(i);
  15. if (node instanceof Element) {
  16. //拿到了<beans>下的子标签
  17. Element ele = (Element) node;
  18. if (delegate.isDefaultNamespace(ele)) {
  19. //如果该标签属于beans的名称空间,则进入这个方法
  20. //xmlns="http://www.springframework.org/schema/beans"
  21. parseDefaultElement(ele, delegate);
  22. }
  23. else {
  24. //如果该标签属于其他的名称空间比如:context,aop等
  25. //xmlns:aop="http://www.springframework.org/schema/aop"
  26. //xmlns:context="http://www.springframework.org/schema/context"
  27. delegate.parseCustomElement(ele);
  28. }
  29. }
  30. }
  31. }
  32. else {
  33. delegate.parseCustomElement(root);
  34. }
  35. }

对以上方法不太了解的可以先看下这篇文章:

https://www.jianshu.com/p/a0cfaedf3fc5

因为component-scan标签属于context名称空间,所以走这个方法。

  1. delegate.parseCustomElement(ele);

这个方法的实现在BeanDefinitionParserDelegate类中

  1. public BeanDefinition parseCustomElement(Element ele) {
  2. return parseCustomElement(ele, null);
  3. }
  4. //containingBd入参传递为null
  5. public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
  6. //获取标签所属的名称空间
  7. //http://www.springframework.org/schema/context
  8. String namespaceUri = getNamespaceURI(ele);
  9. //每个名称空间对应一个处理器,拿到对应context的处理器
  10. NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
  11. if (handler == null) {
  12. error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
  13. return null;
  14. }
  15. //进入这个方法
  16. return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
  17. }

虽然context对应的处理器是ContextNamespaceHandler,但实际上是调用其父类NamespaceHandlerSupport类中的parse方法。

  1. /**
  2. * Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is
  3. * registered for that {@link Element}.
  4. *
  5. * 通过委派给BeanDefinitionParser来解析元素,并为该元素注册
  6. */
  7. @Override
  8. public BeanDefinition parse(Element element, ParserContext parserContext) {
  9. return findParserForElement(element, parserContext).parse(element, parserContext);
  10. }

先查看findParserForElement方法,此方法还是在NamespaceHandlerSupport类中。

  1. /**
  2. * Locates the {@link BeanDefinitionParser} from the register implementations using
  3. * the local name of the supplied {@link Element}.
  4. *
  5. * 通过元素的部分名称,去从注册器实现中定位BeanDefinitionParser
  6. */
  7. private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
  8. //拿到标签的名称(不包含名称空间)
  9. //component-scan
  10. String localName = parserContext.getDelegate().getLocalName(element);
  11. //parsers是一个HashMap,
  12. //在生成处理器的时候,会初始化一系列解析器,每一个解析器对应着一个标签名称
  13. //以名称做key,解析器作为value,放入到parsers属性中
  14. //这里可以通过标签名称拿到对应的解析器
  15. BeanDefinitionParser parser = this.parsers.get(localName);
  16. if (parser == null) {
  17. parserContext.getReaderContext().fatal(
  18. "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
  19. }
  20. return parser;
  21. }

找到解析器后,调用解析器的parse方法。

parse(零)

这里的解析器是ComponentScanBeanDefinitionParser类,进入parse方法查看

  1. /**
  2. * 解析指定的Element,然后注册结果BeanDefinition到内嵌在ParserContext里的bean factory中。
  3. */
  4. @Override
  5. public BeanDefinition parse(Element element, ParserContext parserContext) {
  6. //获取component-scan标签的base-package属性值
  7. //cn.mrdear
  8. String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
  9. //如果有占位符,则解析所有的占位符
  10. basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
  11. //字符串中有" ,;\n\t"等符号就看做分隔符,分割成数组
  12. String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
  13. ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
  14. // Actually scan for bean definitions and register them.
  15. // 扫描bean definition 并注册它们
  16. // 1.配置扫描器
  17. ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
  18. // 2.利用扫描器扫描包,并注册bean definition
  19. Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
  20. // 3. 注册组件
  21. registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
  22. return null;
  23. }

1.configureScanner

跟踪标记1的方法

此方法在ComponentScanBeanDefinitionParser类中实现

  1. // 1.配置扫描器
  2. ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
  3. //进入方法
  4. protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
  5. boolean useDefaultFilters = true;
  6. //拿到component-scan标签的use-default-filters属性,没有配置则为true
  7. if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
  8. useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
  9. }
  10. // Delegate bean definition registration to scanner class.
  11. // 1.1将bean definition的工厂委派给scanner类
  12. ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
  13. //这里将阅读器上下文中拿到的根web应用上下文作为scanner的ResourceLoader,
  14. //根web应用上下文默认实现为XmlWebApplicationContext,实现了ResourceLoader接口,
  15. //所以可以作为ResourceLoader
  16. scanner.setResourceLoader(parserContext.getReaderContext().getResourceLoader());
  17. //初始化scanner时使用默认的StandardEnvironment作为environment,
  18. //这里拿到了阅读器上下文中的environment,StandardServletEnvironment
  19. //其实阅读器中的environment拿的是XmlWebApplicationContext的environment
  20. scanner.setEnvironment(parserContext.getReaderContext().getEnvironment());
  21. //获取代理类的defaults属性中,对标签属性的一些默认设置
  22. scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
  23. //这里为null
  24. scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
  25. //拿到component-scan标签的resource-pattern属性,这里没有设置
  26. if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
  27. scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
  28. }
  29. try {
  30. //1.2解析name-generator属性
  31. parseBeanNameGenerator(element, scanner);
  32. }
  33. catch (Exception ex) {
  34. parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
  35. }
  36. try {
  37. //1.3解析Scope
  38. parseScope(element, scanner);
  39. }
  40. catch (Exception ex) {
  41. parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
  42. }
  43. //1.4解析类过滤器
  44. parseTypeFilters(element, scanner, parserContext);
  45. return scanner;
  46. }

1.1 createScanner

跟踪标记1.1的方法

此方法在ComponentScanBeanDefinitionParser类中实现

  1. // 1.1将bean definition的注册委派给scanner类
  2. ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
  3. //入参传递了bean工厂,useDefaultFilters为true
  4. protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
  5. return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters);
  6. }

看下ClassPathBeanDefinitionScanner类的构造实现

  1. //因为默认的工厂DefaultListableBeanFactory没有实现EnvironmentCapable接口
  2. //所以重新创建了一个environment,与上下文的StandardServletEnvironment不同,
  3. //这个environment是StandardEnvironment类型,在environment初始化的同时,会将
  4. //systemProperties和systemEnvironment读取到environment内部
  5. public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
  6. this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
  7. }
  8. public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {
  9. //调用了父类的构造
  10. super(useDefaultFilters, environment);
  11. Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  12. //拿到bean工厂的引用
  13. this.registry = registry;
  14. // Determine ResourceLoader to use.
  15. // 默认bean工厂没有实现ResourceLoader接口,这里默认使用PathMatchingResourcePatternResolver
  16. // 作为ResourceLoader
  17. if (this.registry instanceof ResourceLoader) {
  18. setResourceLoader((ResourceLoader) this.registry);
  19. }
  20. }

再进入父类构造中查看初始化了哪些属性

进入ClassPathScanningCandidateComponentProvider类中,查看对应的构造方法

  1. public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
  2. //因为useDefaultFilters设置为了true,所以下面的方法会被调用
  3. if (useDefaultFilters) {
  4. registerDefaultFilters();
  5. }
  6. Assert.notNull(environment, "Environment must not be null");
  7. //拿到先前新建的StandardEnvironment引用
  8. this.environment = environment;
  9. }
  10. /**
  11. * Register the default filter for {@link Component @Component}.
  12. * <p>This will implicitly register all annotations that have the
  13. * {@link Component @Component} meta-annotation including the
  14. * {@link Repository @Repository}, {@link Service @Service}, and
  15. * {@link Controller @Controller} stereotype annotations.
  16. * <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
  17. * JSR-330's {@link javax.inject.Named} annotations, if available.
  18. *
  19. * 为@Component注解注册默认的过滤器。
  20. * 隐式的注册所有包含@Component元注解的注解,包括@Repository、@Service、@Controller
  21. * 等老旧的注解。
  22. * 也支持Java EE 6的javax.annotation.ManagedBean和JSR-330的javax.inject.Named注解
  23. */
  24. @SuppressWarnings("unchecked")
  25. protected void registerDefaultFilters() {
  26. //includeFilters是一个LinkedList,存放注解类型过滤器,
  27. //只有符合过滤器的注解类型才能生成bean definition
  28. //1.1.1了解下AnnotationTypeFilter的构造实现,注解类型为Component
  29. this.includeFilters.add(new AnnotationTypeFilter(Component.class));
  30. //拿到该类的类加载器
  31. ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
  32. try {
  33. //1.1.2查看注解类型为ManagedBean的AnnotationTypeFilter构造实现
  34. this.includeFilters.add(new AnnotationTypeFilter(
  35. ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
  36. logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
  37. }
  38. catch (ClassNotFoundException ex) {
  39. // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
  40. }
  41. try {
  42. //Named注解同1.1.2,
  43. //但是这里没有相关jar包,所以没有javax.inject.Named这个类,抛出异常,空捕获跳出
  44. this.includeFilters.add(new AnnotationTypeFilter(
  45. ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
  46. logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
  47. }
  48. catch (ClassNotFoundException ex) {
  49. // JSR-330 API not available - simply skip.
  50. }
  51. }

1.1.1 AnnotationTypeFilter

跟踪标记1.1.1的方法

  1. //1.1.1了解下AnnotationTypeFilter的构造实现
  2. new AnnotationTypeFilter(Component.class)
  3. /**
  4. * Create a new AnnotationTypeFilter for the given annotation type.
  5. * This filter will also match meta-annotations. To disable the
  6. * meta-annotation matching, use the constructor that accepts a
  7. * '{@code considerMetaAnnotations}' argument. The filter will
  8. * not match interfaces.
  9. *
  10. * 通过给定的注解类型创建一个新的注解类型过滤器
  11. * 这个过滤器还会匹配元注解
  12. * 如果要禁用元注解匹配,可以使用接受considerMetaAnnotations参数的构造方法。
  13. * 这个过滤器不会匹配接口
  14. */
  15. public AnnotationTypeFilter(Class<? extends Annotation> annotationType) {
  16. this(annotationType, true, false);
  17. }
  18. /**
  19. * 注意上一层调用构造时的入参,默认considerMetaAnnotations为true,considerInterfaces为false
  20. * 这说明注解中如果它的元注解匹配过滤器,那么也算是匹配。
  21. * 过滤的时候不考虑是接口的情况
  22. */
  23. public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) {
  24. //isAnnotationPresent方法是用来查看annotationType上是否有Inherited注解
  25. //其boolean值赋值给父类AbstractTypeHierarchyTraversingFilter的属性considerInherited中
  26. super(annotationType.isAnnotationPresent(Inherited.class), considerInterfaces);
  27. this.annotationType = annotationType;
  28. this.considerMetaAnnotations = considerMetaAnnotations;
  29. }

1.1.2 AnnotationTypeFilter

跟踪标记1.1.2的方法

  1. //1.1.2查看注解类型为ManagedBean的AnnotationTypeFilter构造实现
  2. new AnnotationTypeFilter(
  3. ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false);

首先通过forName方法,拿到字符串javax.annotation.ManagedBean对应的Class,然后调用AnnotationTypeFilter的构造。

  1. /**
  2. * 上一层传参时considerMetaAnnotations为false,说明不用考虑注解上的元注解,这个注解不匹配过滤器就过滤掉
  3. */
  4. public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations) {
  5. this(annotationType, considerMetaAnnotations, false);
  6. }
  7. //considerInterfaces依然为false
  8. public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) {
  9. //ManagedBean的元注解上依然没有Inherited,所以considerInherited为false
  10. super(annotationType.isAnnotationPresent(Inherited.class), considerInterfaces);
  11. this.annotationType = annotationType;
  12. this.considerMetaAnnotations = considerMetaAnnotations;
  13. }

1.2 parseBeanNameGenerator

跟踪标记1.2的方法

在ComponentScanBeanDefinitionParser类中实现

  1. //1.2解析name-generator属性
  2. parseBeanNameGenerator(element, scanner);
  3. protected void parseBeanNameGenerator(Element element, ClassPathBeanDefinitionScanner scanner) {
  4. //component-scan标签的name-generator属性,这里没有设置,跳过
  5. if (element.hasAttribute(NAME_GENERATOR_ATTRIBUTE)) {
  6. BeanNameGenerator beanNameGenerator = (BeanNameGenerator) instantiateUserDefinedStrategy(
  7. element.getAttribute(NAME_GENERATOR_ATTRIBUTE), BeanNameGenerator.class,
  8. scanner.getResourceLoader().getClassLoader());
  9. scanner.setBeanNameGenerator(beanNameGenerator);
  10. }
  11. }

1.3 parseScope

跟踪标记1.3的方法

在ComponentScanBeanDefinitionParser类中实现

  1. //1.3 解析Scope
  2. parseScope(element, scanner);
  3. protected void parseScope(Element element, ClassPathBeanDefinitionScanner scanner) {
  4. // Register ScopeMetadataResolver if class name provided.
  5. // 如果类名被提供,则注册ScopeMetadataResolver
  6. // 标签上有无scope-resolver属性
  7. if (element.hasAttribute(SCOPE_RESOLVER_ATTRIBUTE)) {
  8. // 如果还同时添加了scoped-proxy属性则报错
  9. if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {
  10. throw new IllegalArgumentException(
  11. "Cannot define both 'scope-resolver' and 'scoped-proxy' on <component-scan> tag");
  12. }
  13. ScopeMetadataResolver scopeMetadataResolver = (ScopeMetadataResolver) instantiateUserDefinedStrategy(
  14. element.getAttribute(SCOPE_RESOLVER_ATTRIBUTE), ScopeMetadataResolver.class,
  15. scanner.getResourceLoader().getClassLoader());
  16. scanner.setScopeMetadataResolver(scopeMetadataResolver);
  17. }
  18. // 标签上有无scoped-proxy属性
  19. if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {
  20. String mode = element.getAttribute(SCOPED_PROXY_ATTRIBUTE);
  21. if ("targetClass".equals(mode)) {
  22. scanner.setScopedProxyMode(ScopedProxyMode.TARGET_CLASS);
  23. }
  24. else if ("interfaces".equals(mode)) {
  25. scanner.setScopedProxyMode(ScopedProxyMode.INTERFACES);
  26. }
  27. else if ("no".equals(mode)) {
  28. scanner.setScopedProxyMode(ScopedProxyMode.NO);
  29. }
  30. else {
  31. throw new IllegalArgumentException("scoped-proxy only supports 'no', 'interfaces' and 'targetClass'");
  32. }
  33. }
  34. }

1.4 parseTypeFilters

跟踪标记1.4的方法

在ComponentScanBeanDefinitionParser类中实现

  1. //1.4解析类过滤器
  2. parseTypeFilters(element, scanner, parserContext);
  3. protected void parseTypeFilters(Element element, ClassPathBeanDefinitionScanner scanner, ParserContext parserContext) {
  4. // Parse exclude and include filter elements.
  5. // 解析包含和不包含过滤器元素
  6. //拿到根应用上下文的类加载器
  7. ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
  8. //拿到所有的子节点
  9. NodeList nodeList = element.getChildNodes();
  10. for (int i = 0; i < nodeList.getLength(); i++) {
  11. Node node = nodeList.item(i);
  12. //拿到的子节点是不是子标签
  13. if (node.getNodeType() == Node.ELEMENT_NODE) {
  14. //获取子标签的部分名称(不包含名称空间)
  15. String localName = parserContext.getDelegate().getLocalName(node);
  16. try {
  17. //是include-filter标签的情况,上下两个调用的同一个方法,跟踪其中一个
  18. if (INCLUDE_FILTER_ELEMENT.equals(localName)) {
  19. TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
  20. scanner.addIncludeFilter(typeFilter);
  21. }
  22. //是exclude-filter标签的情况
  23. else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {
  24. TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
  25. scanner.addExcludeFilter(typeFilter);
  26. }
  27. }
  28. catch (Exception ex) {
  29. parserContext.getReaderContext().error(
  30. ex.getMessage(), parserContext.extractSource(element), ex.getCause());
  31. }
  32. }
  33. }
  34. }

跟踪createTypeFilter方法

  1. protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader, ParserContext parserContext) {
  2. //获取标签上的type属性和expression属性对应的值
  3. String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
  4. String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
  5. //expression可能带有占位符,如果有则解析占位符
  6. expression = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(expression);
  7. try {
  8. //xml文件中type填写的是annotation,所以走这个方法
  9. if ("annotation".equals(filterType)) {
  10. //将xml中的"org.springframework.stereotype.Controller"字符串解析为Class
  11. //构造已经看过,默认considerMetaAnnotations为true,considerInterfaces为false
  12. return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
  13. }
  14. else if ("assignable".equals(filterType)) {
  15. return new AssignableTypeFilter(classLoader.loadClass(expression));
  16. }
  17. else if ("aspectj".equals(filterType)) {
  18. return new AspectJTypeFilter(expression, classLoader);
  19. }
  20. else if ("regex".equals(filterType)) {
  21. return new RegexPatternTypeFilter(Pattern.compile(expression));
  22. }
  23. else if ("custom".equals(filterType)) {
  24. Class<?> filterClass = classLoader.loadClass(expression);
  25. if (!TypeFilter.class.isAssignableFrom(filterClass)) {
  26. throw new IllegalArgumentException(
  27. "Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
  28. }
  29. return (TypeFilter) BeanUtils.instantiateClass(filterClass);
  30. }
  31. else {
  32. throw new IllegalArgumentException("Unsupported filter type: " + filterType);
  33. }
  34. }
  35. catch (ClassNotFoundException ex) {
  36. throw new FatalBeanException("Type filter class not found: " + expression, ex);
  37. }
  38. }

最后scanner的includeFilters属性中,默认添加了org.springframework.stereotype.Component的注解过滤器和javax.annotation.ManagedBean的注解过滤器。

scanner的excludeFilters属性中,自定义添加了xml配置文件中的org.springframework.stereotype.Controller注解过滤器和org.springframework.web.bind.annotation.RestController注解过滤器。

2.doScan

跟踪标记2的方法

此方法在ClassPathBeanDefinitionScanner类中实现

  1. // 2.利用扫描器扫描包,并注册bean definition
  2. Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
  3. /**
  4. * Perform a scan within the specified base packages,
  5. * returning the registered bean definitions.
  6. * <p>This method does <i>not</i> register an annotation config processor
  7. * but rather leaves this up to the caller.
  8. *
  9. * 扫描指定包,返回被注册的bean definitions
  10. * 这个方法不会注册annotation config processor,交由调用者处理
  11. */
  12. protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
  13. Assert.notEmpty(basePackages, "At least one base package must be specified");
  14. Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
  15. //根据配置,这里就只有一个"cn.mrdear"
  16. for (String basePackage : basePackages) {
  17. //2.1扫描候选者的class path
  18. Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
  19. for (BeanDefinition candidate : candidates) {
  20. //2.2解析@scope注解
  21. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
  22. candidate.setScope(scopeMetadata.getScopeName());
  23. //2.3AnnotatedBeanDefinition的默认名称生成规则
  24. String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
  25. if (candidate instanceof AbstractBeanDefinition) {
  26. //2.4给beanDefinition设置默认值、自动注入的候选者
  27. postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
  28. }
  29. if (candidate instanceof AnnotatedBeanDefinition) {
  30. //2.5拿到类上其他的context名称空间的注解,如果有的话,获取其value属性
  31. AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
  32. }
  33. //2.6检查beanName是否正确匹配对应的bean Definition,该名称是否已经被注册
  34. if (checkCandidate(beanName, candidate)) {
  35. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
  36. //应用Scope代理模式
  37. definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  38. beanDefinitions.add(definitionHolder);
  39. //注册bean definition
  40. registerBeanDefinition(definitionHolder, this.registry);
  41. }
  42. }
  43. }
  44. return beanDefinitions;
  45. }

2.1 findCandidateComponents

跟踪标记2.1的方法

在ClassPathScanningCandidateComponentProvider类中实现

ClassPathScanningCandidateComponentProvider是ClassPathBeanDefinitionScanner的父类

  1. //2.1扫描候选者的class path
  2. Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
  3. public Set<BeanDefinition> findCandidateComponents(String basePackage) {
  4. Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
  5. try {
  6. //给包名添加上"classpath*:"的前缀和"**/*.class"的后缀
  7. //最后结果:classpath*:cn/mrdear/**/*.class
  8. String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
  9. resolveBasePackage(basePackage) + "/" + this.resourcePattern;
  10. //将包下的所有class文件用Resource的方式描述
  11. //Resource--资源描述符
  12. //里面的实现非常大,有兴趣可以自己看看。
  13. //主要是将packageSearchPath分成classpath,包名,后缀名三部分进行处理,又根据有无*或者?
  14. //等表达式,处理方式有所不同
  15. Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
  16. boolean traceEnabled = logger.isTraceEnabled();
  17. boolean debugEnabled = logger.isDebugEnabled();
  18. //对每个class进行处理
  19. for (Resource resource : resources) {
  20. if (traceEnabled) {
  21. logger.trace("Scanning " + resource);
  22. }
  23. //是否非目录,可读
  24. if (resource.isReadable()) {
  25. try {
  26. //这个metadataReader包含class文件中,类上的注解
  27. //方法的注解,所使用注解的元注解等描述
  28. //在获取metadataReader的同时,在CachingMetadataReaderFactory类的
  29. //metadataReaderCache属性中存放了一份。此属性是LinkedHashMap
  30. MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
  31. //2.1.1判断metadataReader能否通过注解类型过滤器过滤
  32. if (isCandidateComponent(metadataReader)) {
  33. //创建bean definition,拿到metadataReader的beanClass
  34. //保存metadataReader的annotationMetadata的引用
  35. ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
  36. //取得资源描述符的引用
  37. sbd.setResource(resource);
  38. sbd.setSource(resource);
  39. //2.1.2查看类是否具体且独立
  40. if (isCandidateComponent(sbd)) {
  41. if (debugEnabled) {
  42. //确定候选组件class
  43. logger.debug("Identified candidate component class: " + resource);
  44. }
  45. candidates.add(sbd);
  46. }
  47. else {
  48. if (debugEnabled) {
  49. //被忽略,不是一个具体的顶层class
  50. logger.debug("Ignored because not a concrete top-level class: " + resource);
  51. }
  52. }
  53. }
  54. else {
  55. if (traceEnabled) {
  56. //被忽略,不匹配任何过滤器
  57. logger.trace("Ignored because not matching any filter: " + resource);
  58. }
  59. }
  60. }
  61. catch (Throwable ex) {
  62. throw new BeanDefinitionStoreException(
  63. //失败读取候选组件
  64. "Failed to read candidate component class: " + resource, ex);
  65. }
  66. }
  67. else {
  68. if (traceEnabled) {
  69. //不可读,忽略
  70. logger.trace("Ignored because not readable: " + resource);
  71. }
  72. }
  73. }
  74. }
  75. catch (IOException ex) {
  76. //扫描类路径时IO异常
  77. throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
  78. }
  79. //最后返回候选的bean definition
  80. return candidates;
  81. }

我这里返回的就只有两个类,加了@ControllerAdvice的GlobalException、加了@Service的BookServiceImpl。

其余的要么是接口,要么没被扫描,要么被过滤器过滤了,以下是我项目中所有class:

2.1.1 isCandidateComponent

跟踪标记2.1.1的方法

在ClassPathScanningCandidateComponentProvider类中实现

  1. //2.1.1判断metadataReader能否通过注解类型过滤器过滤
  2. isCandidateComponent(metadataReader)
  3. /**
  4. * Determine whether the given class does not match any exclude filter
  5. * and does match at least one include filter.
  6. *
  7. * 不匹配任何exclude filter,至少匹配一个include filter.
  8. * 才能确定其为候选人
  9. */
  10. protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
  11. for (TypeFilter tf : this.excludeFilters) {
  12. //2.1.1.1跟踪match方法
  13. //如果metadataReader中有注解匹配exclude过滤器的注解,则返回false
  14. if (tf.match(metadataReader, this.metadataReaderFactory)) {
  15. return false;
  16. }
  17. }
  18. for (TypeFilter tf : this.includeFilters) {
  19. //如果metadataReader中有注解匹配include过滤器的注解,则进入条件
  20. if (tf.match(metadataReader, this.metadataReaderFactory)) {
  21. //2.1.1.2是否有@Conditional注解,进行相关处理
  22. return isConditionMatch(metadataReader);
  23. }
  24. }
  25. return false;
  26. }

过滤器中存放的都是AnnotationTypeFilter类型

TypeFilter是其顶层接口

match方法主要是在AbstractTypeHierarchyTraversingFilter抽象类中实现

2.1.1.1 match

跟踪标记2.1.1.1的方法

在AbstractTypeHierarchyTraversingFilter类中实现

  1. //2.1.1.1跟踪match方法
  2. tf.match(metadataReader, this.metadataReaderFactory)
  3. @Override
  4. public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
  5. throws IOException {
  6. // This method optimizes avoiding unnecessary creation of ClassReaders
  7. // as well as visiting over those readers.
  8. // 此方法做了优化,避免不必要的ClassReaders创建以及对它们的访问
  9. // matchSelf方法判断metadataReader中相关class的注解有没有包含这个过滤器的注解
  10. // 如果没有,但是过滤器的considerMetaAnnotations属性设置为true,
  11. // 那么再判断class所有注解的元注解中,有没有包含这个过滤器的注解
  12. // 有就返回true,进入条件
  13. if (matchSelf(metadataReader)) {
  14. return true;
  15. }
  16. ClassMetadata metadata = metadataReader.getClassMetadata();
  17. // 默认返回false,不进入条件
  18. if (matchClassName(metadata.getClassName())) {
  19. return true;
  20. }
  21. //considerInherited这个属性前面跟踪的过滤器中都为false
  22. //和过滤器的注解有关,其元注解包含Inherited,
  23. //那么considerInherited属性就为true
  24. if (this.considerInherited) {
  25. if (metadata.hasSuperClass()) {
  26. // Optimization to avoid creating ClassReader for super class.
  27. Boolean superClassMatch = matchSuperClass(metadata.getSuperClassName());
  28. if (superClassMatch != null) {
  29. if (superClassMatch.booleanValue()) {
  30. return true;
  31. }
  32. }
  33. else {
  34. // Need to read super class to determine a match...
  35. try {
  36. if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
  37. return true;
  38. }
  39. }
  40. catch (IOException ex) {
  41. logger.debug("Could not read super class [" + metadata.getSuperClassName() +
  42. "] of type-filtered class [" + metadata.getClassName() + "]");
  43. }
  44. }
  45. }
  46. }
  47. //considerInterfaces属性在AnnotationTypeFilter构造器中都默认被设置为false
  48. if (this.considerInterfaces) {
  49. for (String ifc : metadata.getInterfaceNames()) {
  50. // Optimization to avoid creating ClassReader for super class
  51. Boolean interfaceMatch = matchInterface(ifc);
  52. if (interfaceMatch != null) {
  53. if (interfaceMatch.booleanValue()) {
  54. return true;
  55. }
  56. }
  57. else {
  58. // Need to read interface to determine a match...
  59. try {
  60. if (match(ifc, metadataReaderFactory)) {
  61. return true;
  62. }
  63. }
  64. catch (IOException ex) {
  65. logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
  66. metadata.getClassName() + "]");
  67. }
  68. }
  69. }
  70. }
  71. return false;
  72. }
2.1.1.2 isConditionMatch

跟踪标记2.1.1.2的方法

在ClassPathScanningCandidateComponentProvider类中实现

  1. //2.1.1.2是否有@Conditional注解,进行相关处理
  2. isConditionMatch(metadataReader);
  3. /**
  4. * Determine whether the given class is a candidate component based on any
  5. * {@code @Conditional} annotations.
  6. *
  7. * 确定指定类是否是基于任何@Conditional注解的候选组件
  8. */
  9. private boolean isConditionMatch(MetadataReader metadataReader) {
  10. if (this.conditionEvaluator == null) {
  11. this.conditionEvaluator = new ConditionEvaluator(getRegistry(), getEnvironment(), getResourceLoader());
  12. }
  13. //跟踪这个方法
  14. return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
  15. }

于是进入ConditionEvaluator的shouldSkip方法

  1. /**
  2. * Determine if an item should be skipped based on {@code @Conditional} annotations.
  3. * The {@link ConfigurationPhase} will be deduced from the type of item (i.e. a
  4. * {@code @Configuration} class will be {@link ConfigurationPhase#PARSE_CONFIGURATION})
  5. *
  6. * 根据@Conditional注解确定一个子项是否应该被跳过
  7. * 从子项的类型可以推导ConfigurationPhase,比如@Configuration class就是
  8. * ConfigurationPhase#PARSE_CONFIGURATION--解析配置
  9. */
  10. public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
  11. return shouldSkip(metadata, null);
  12. }
  13. //这个方法就不跟了,如果要了解condition注解的用法,可以详细了解该方法
  14. public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
  15. //类上注解或者注解上的元注解不包含Conditional注解就返回false
  16. if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
  17. return false;
  18. }
  19. if (phase == null) {
  20. if (metadata instanceof AnnotationMetadata &&
  21. ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
  22. return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
  23. }
  24. return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
  25. }
  26. List<Condition> conditions = new ArrayList<Condition>();
  27. for (String[] conditionClasses : getConditionClasses(metadata)) {
  28. for (String conditionClass : conditionClasses) {
  29. Condition condition = getCondition(conditionClass, this.context.getClassLoader());
  30. conditions.add(condition);
  31. }
  32. }
  33. AnnotationAwareOrderComparator.sort(conditions);
  34. for (Condition condition : conditions) {
  35. ConfigurationPhase requiredPhase = null;
  36. if (condition instanceof ConfigurationCondition) {
  37. requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
  38. }
  39. if (requiredPhase == null || requiredPhase == phase) {
  40. if (!condition.matches(this.context, metadata)) {
  41. return true;
  42. }
  43. }
  44. }
  45. return false;
  46. }

2.1.2 isCandidateComponent

跟踪标记2.1.2的方法

在ClassPathScanningCandidateComponentProvider类中实现

  1. //2.1.2查看类是否具体且独立
  2. isCandidateComponent(sbd)
  3. /**
  4. * Determine whether the given bean definition qualifies as candidate.
  5. * <p>The default implementation checks whether the class is concrete
  6. * (i.e. not abstract and not an interface). Can be overridden in subclasses.
  7. *
  8. * 确定bean definition qualifies能否作为候选
  9. * 默认实现会检查class是否具体(不是抽象、不是接口)。可以被子类覆盖
  10. */
  11. protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
  12. //看下这两个判断的含义
  13. return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent());
  14. }
  15. //不能是接口和抽象类
  16. public boolean isConcrete() {
  17. return !(this.isInterface || this.isAbstract);
  18. }
  19. //要么是顶层class,要么是被嵌套的class(静态内部类),但是被嵌套的class必须能够从
  20. //封闭的class中独立构造,才能说明此class是独立的。
  21. public boolean isIndependent() {
  22. //没有封闭的class或者是独立的内部类
  23. return (this.enclosingClassName == null || this.independentInnerClass);
  24. }

2.2 resolveScopeMetadata

跟踪标记2.2的方法

在AnnotationScopeMetadataResolver类中实现

  1. //2.2解析@scope注解
  2. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
  3. /**
  4. * Resolve the {@link ScopeMetadata} appropriate to the supplied
  5. * bean {@code definition}.
  6. * <p>Implementations can of course use any strategy they like to
  7. * determine the scope metadata, but some implementations that spring
  8. * immediately to mind might be to use source level annotations
  9. * present on {@link BeanDefinition#getBeanClassName() the class} of the
  10. * supplied {@code definition}, or to use metadata present in the
  11. * {@link BeanDefinition#attributeNames()} of the supplied {@code definition}.
  12. *
  13. * 解析适用于BeanDefinition的ScopeMetadata
  14. * 实现当然可以使用任何喜欢的策略去确定scope metadata,但是spring的实现立马
  15. * 想到的是使用source level注解在BeanDefinition对应的class上
  16. * 或者将metadata存放于BeanDefinition的属性中
  17. */
  18. public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
  19. //默认单例,无代理
  20. ScopeMetadata metadata = new ScopeMetadata();
  21. if (definition instanceof AnnotatedBeanDefinition) {
  22. AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
  23. //拿到指定类上的@scope注解的所有属性
  24. AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
  25. annDef.getMetadata(), this.scopeAnnotationType);
  26. if (attributes != null) {
  27. metadata.setScopeName(attributes.getString("value"));
  28. ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
  29. if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
  30. proxyMode = this.defaultProxyMode;
  31. }
  32. metadata.setScopedProxyMode(proxyMode);
  33. }
  34. }
  35. return metadata;
  36. }

2.3 generateBeanName

跟踪标记2.3的方法

在AnnotationBeanNameGenerator类中实现

  1. //2.3AnnotatedBeanDefinition的默认名称生成规则
  2. String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
  3. public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
  4. if (definition instanceof AnnotatedBeanDefinition) {
  5. //先进入这个方法查看
  6. String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
  7. if (StringUtils.hasText(beanName)) {
  8. // Explicit bean name found.
  9. // 发现明确bean Name
  10. return beanName;
  11. }
  12. }
  13. // Fallback: generate a unique default bean name.
  14. // 回退:生成一个唯一的默认beanName
  15. return buildDefaultBeanName(definition, registry);
  16. }
  17. /**
  18. * Derive a bean name from one of the annotations on the class.
  19. *
  20. * 从类上的一个注解中,派生出bean name
  21. */
  22. protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
  23. AnnotationMetadata amd = annotatedDef.getMetadata();
  24. //嘉定拿的是org.springframework.web.bind.annotation.ControllerAdvice
  25. Set<String> types = amd.getAnnotationTypes();
  26. String beanName = null;
  27. for (String type : types) {
  28. //拿到@ControllerAdvice上的所有的属性
  29. AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
  30. //将@ControllerAdvice注解名,@ControllerAdvice的元注解,@ControllerAdvice上的属性
  31. //当做参数传递
  32. //进入这个方法
  33. if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
  34. //获取注解上的value属性对应的值
  35. Object value = attributes.get("value");
  36. if (value instanceof String) {
  37. String strVal = (String) value;
  38. if (StringUtils.hasLength(strVal)) {
  39. if (beanName != null && !strVal.equals(beanName)) {
  40. throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
  41. "component names: '" + beanName + "' versus '" + strVal + "'");
  42. }
  43. //用value属性对应的值作为beanName
  44. beanName = strVal;
  45. }
  46. }
  47. }
  48. }
  49. return beanName;
  50. }
  51. /**
  52. * Check whether the given annotation is a stereotype that is allowed
  53. * to suggest a component name through its annotation {@code value()}.
  54. *
  55. * 检查注解是不是stereotype类型,如果是的话,可以用注解的value()属性,作为组件名称
  56. */
  57. protected boolean isStereotypeWithNameValue(String annotationType,
  58. Set<String> metaAnnotationTypes, Map<String, Object> attributes) {
  59. //注解是不是stereotype类型,主要看他是不是component注解、ManagedBean注解或者Named注解
  60. //或者注解的元注解包含component注解
  61. boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
  62. (metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
  63. annotationType.equals("javax.annotation.ManagedBean") ||
  64. annotationType.equals("javax.inject.Named");
  65. //是stereotype类型,且有value属性的注解,返回true
  66. return (isStereotype && attributes != null && attributes.containsKey("value"));
  67. }

上面看了beanDefinition是AnnotatedBeanDefinition类型情况下,beanName怎样生成。但是如果class上的stereotype注解,没有给value属性赋值,那么又是怎样生成beanName的?

查看其默认的beanName生成方式:

  1. buildDefaultBeanName(definition, registry);

此方法的实现还是在AnnotationBeanNameGenerator类中:

  1. /**
  2. * Derive a default bean name from the given bean definition.
  3. * <p>The default implementation delegates to {@link #buildDefaultBeanName(BeanDefinition)}.
  4. *
  5. * 从给定的bean definition派生一个默认bean Name
  6. */
  7. protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
  8. return buildDefaultBeanName(definition);
  9. }
  10. /**
  11. * Derive a default bean name from the given bean definition.
  12. * <p>The default implementation simply builds a decapitalized version
  13. * of the short class name: e.g. "mypackage.MyJdbcDao" -> "myJdbcDao".
  14. * <p>Note that inner classes will thus have names of the form
  15. * "outerClassName.InnerClassName", which because of the period in the
  16. * name may be an issue if you are autowiring by name.
  17. *
  18. * 默认的实现是构建一个首字母小写(像变量一样的命名方式)的简短类名。
  19. * 注意内部类因此会是这样的格式"outerClassName.InnerClassName"
  20. * 如果通过名称自动注入,中间的点就可能引发问题
  21. */
  22. protected String buildDefaultBeanName(BeanDefinition definition) {
  23. //cn.mrdear.exception.GlobalException => GlobalException
  24. String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
  25. //此方法将字符串首字符大写转小写,但是如果第二个字符也是大写就不进行转换,因为他可能是
  26. //这样的格式--> "URL"
  27. return Introspector.decapitalize(shortClassName);
  28. }

2.4 postProcessBeanDefinition

跟踪标记2.4的方法

在ClassPathBeanDefinitionScanner类中实现

  1. //2.4给beanDefinition设置默认值,自动注入的候选者
  2. postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
  3. /**
  4. * Apply further settings to the given bean definition,
  5. * beyond the contents retrieved from scanning the component class.
  6. *
  7. * 除从组件class扫描检索的内容外,应用更多的设置到bean definition
  8. */
  9. protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
  10. //扫描器中的Defaults应用到beanDefinition中
  11. beanDefinition.applyDefaults(this.beanDefinitionDefaults);
  12. if (this.autowireCandidatePatterns != null) {
  13. //设置自动注入候选者
  14. beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
  15. }
  16. }

2.5 processCommonDefinitionAnnotations

跟踪标记2.5的方法

在AnnotationConfigUtils类中实现

  1. //2.5拿到类上其他的context名称空间的注解,如果有的话,获取其value属性
  2. AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
  3. public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
  4. processCommonDefinitionAnnotations(abd, abd.getMetadata());
  5. }
  6. static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
  7. //类上是否有Lazy注解,或者注解的元注解上有Lazy注解
  8. if (metadata.isAnnotated(Lazy.class.getName())) {
  9. //拿到@Lazy注解上的所有属性,获取其value属性的值
  10. abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value"));
  11. }
  12. //metadata不属于abd的情况
  13. else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) {
  14. abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value"));
  15. }
  16. //类上是否有Primary注解,或者注解的元注解上有Primary注解
  17. if (metadata.isAnnotated(Primary.class.getName())) {
  18. abd.setPrimary(true);
  19. }
  20. //类上是否有DependsOn注解,或者注解的元注解上有DependsOn注解
  21. if (metadata.isAnnotated(DependsOn.class.getName())) {
  22. //拿到@DependsOn注解上的所有属性,获取其value属性的值
  23. abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value"));
  24. }
  25. if (abd instanceof AbstractBeanDefinition) {
  26. AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
  27. //类上是否有Role注解,或者注解的元注解上有Role注解
  28. if (metadata.isAnnotated(Role.class.getName())) {
  29. //拿到@Role注解上的所有属性,获取其value属性的值
  30. absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue());
  31. }
  32. //类上是否有Description注解,或者注解的元注解上有Role注解
  33. if (metadata.isAnnotated(Description.class.getName())) {
  34. //拿到@Description注解上的所有属性,获取其value属性的值
  35. absBd.setDescription(attributesFor(metadata, Description.class).getString("value"));
  36. }
  37. }
  38. }

2.6 checkCandidate

跟踪标记2.6的方法

在ClassPathBeanDefinitionScanner类中实现

  1. //2.6检查beanName是否正确匹配对应的bean Definition,该名称是否已经被注册
  2. checkCandidate(beanName, candidate)
  3. protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
  4. //工厂中没有注册这个beanName,返回true
  5. if (!this.registry.containsBeanDefinition(beanName)) {
  6. return true;
  7. }
  8. BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
  9. BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
  10. if (originatingDef != null) {
  11. existingDef = originatingDef;
  12. }
  13. //如果已存在的和入参的beanDefinition能够兼容,就返回false,否则抛出异常
  14. if (isCompatible(beanDefinition, existingDef)) {
  15. return false;
  16. }
  17. throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
  18. "' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
  19. "non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
  20. }

3.registerComponents

跟踪标记3的方法

此方法在ComponentScanBeanDefinitionParser类中实现

  1. // 3. 注册组件
  2. registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
  3. protected void registerComponents(
  4. XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {
  5. //这里返回的是null
  6. Object source = readerContext.extractSource(element);
  7. //拿到组合组件定义对象,以完整标签名做为name
  8. CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
  9. for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
  10. //分两部分看
  11. //3.1bean组件定义的构造初始化
  12. //将创建好的BeanComponentDefinition放入到组合组件定义的nestedComponents中
  13. //nestedComponents是一个LinkedList
  14. compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
  15. }
  16. // Register annotation config processors, if necessary.
  17. // 如果必要的话,注册注解配置处理器
  18. boolean annotationConfig = true;
  19. //拿到component-scan标签的annotation-config属性
  20. if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
  21. //默认设置为true
  22. annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
  23. }
  24. if (annotationConfig) {
  25. //3.2查看怎么注册注解配置处理器
  26. Set<BeanDefinitionHolder> processorDefinitions =
  27. AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
  28. for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
  29. //如果有为被注册的处理器,注册完成后再添加到组合组件定义中
  30. compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
  31. }
  32. }
  33. //这里空实现
  34. readerContext.fireComponentRegistered(compositeDef);
  35. }

3.1 BeanComponentDefinition

跟踪标记3.1的方法

进入BeanComponentDefinition的构造方法

  1. //3.1bean组件定义的构造初始化
  2. new BeanComponentDefinition(beanDefHolder)
  3. public BeanComponentDefinition(BeanDefinitionHolder holder) {
  4. //先看父类构造做了什么操作
  5. super(holder);
  6. //找到这个class中,属性为注册到工厂中的bean deifiniion或者BeanReference的集合
  7. findInnerBeanDefinitionsAndBeanReferences(holder.getBeanDefinition());
  8. }
  9. /**
  10. * 其实BeanComponentDefinition就是BeanDefinitionHolder的子类
  11. *
  12. * Copy constructor: Create a new BeanDefinitionHolder with the
  13. * same contents as the given BeanDefinitionHolder instance.
  14. * <p>Note: The wrapped BeanDefinition reference is taken as-is;
  15. * it is {@code not} deeply copied.
  16. *
  17. * 复制构造:利用给定的beanDefinitionHolder实例,创建一个新的BeanDefinitionHolder
  18. */
  19. public BeanDefinitionHolder(BeanDefinitionHolder beanDefinitionHolder) {
  20. Assert.notNull(beanDefinitionHolder, "BeanDefinitionHolder must not be null");
  21. this.beanDefinition = beanDefinitionHolder.getBeanDefinition();
  22. this.beanName = beanDefinitionHolder.getBeanName();
  23. this.aliases = beanDefinitionHolder.getAliases();
  24. }

然后再了解下findInnerBeanDefinitionsAndBeanReferences方法做了什么事情

  1. private void findInnerBeanDefinitionsAndBeanReferences(BeanDefinition beanDefinition) {
  2. List<BeanDefinition> innerBeans = new ArrayList<BeanDefinition>();
  3. List<BeanReference> references = new ArrayList<BeanReference>();
  4. PropertyValues propertyValues = beanDefinition.getPropertyValues();
  5. //拿到类中所有的属性值,如果属性为在bean工厂中注册的bean definition、或者
  6. //有BeanReference--非实体bean只是逻辑上的引用,则放入集合
  7. for (int i = 0; i < propertyValues.getPropertyValues().length; i++) {
  8. PropertyValue propertyValue = propertyValues.getPropertyValues()[i];
  9. Object value = propertyValue.getValue();
  10. if (value instanceof BeanDefinitionHolder) {
  11. innerBeans.add(((BeanDefinitionHolder) value).getBeanDefinition());
  12. }
  13. else if (value instanceof BeanDefinition) {
  14. innerBeans.add((BeanDefinition) value);
  15. }
  16. else if (value instanceof BeanReference) {
  17. references.add((BeanReference) value);
  18. }
  19. }
  20. this.innerBeanDefinitions = innerBeans.toArray(new BeanDefinition[innerBeans.size()]);
  21. this.beanReferences = references.toArray(new BeanReference[references.size()]);
  22. }

3.2 registerAnnotationConfigProcessors

跟踪标记3.2的方法

进入AnnotationConfigUtils的构造方法

  1. //3.2查看怎么注册注解配置处理器
  2. Set<BeanDefinitionHolder> processorDefinitions =
  3. AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
  4. /**
  5. * Register all relevant annotation post processors in the given registry.
  6. *
  7. * 注册所有相关的注解后处理器到指定工厂中
  8. */
  9. public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
  10. BeanDefinitionRegistry registry, Object source) {
  11. DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
  12. if (beanFactory != null) {
  13. //bean工厂的依赖比较器不是AnnotationAwareOrderComparator的实例,
  14. //就换成AnnotationAwareOrderComparator
  15. if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
  16. beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
  17. }
  18. //bean工厂的自动注入候选解析器不是ContextAnnotationAutowireCandidateResolver的实例,
  19. //就换成ContextAnnotationAutowireCandidateResolver
  20. if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
  21. beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
  22. }
  23. }
  24. Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
  25. //工厂中没有注册internalConfigurationAnnotationProcessor,则注册
  26. if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  27. RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
  28. def.setSource(source);
  29. beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
  30. }
  31. //工厂中没有注册internalAutowiredAnnotationProcessor,则注册
  32. if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  33. RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
  34. def.setSource(source);
  35. beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
  36. }
  37. //工厂中没有注册internalRequiredAnnotationProcessor,则注册
  38. if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  39. RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
  40. def.setSource(source);
  41. beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
  42. }
  43. // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
  44. // 检查是否支持JSR-250,如果有则添加CommonAnnotationBeanPostProcessor
  45. if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  46. RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
  47. def.setSource(source);
  48. beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
  49. }
  50. // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
  51. // 检查JPA支持,如果有则添加PersistenceAnnotationBeanPostProcessor
  52. if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  53. RootBeanDefinition def = new RootBeanDefinition();
  54. try {
  55. def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
  56. AnnotationConfigUtils.class.getClassLoader()));
  57. }
  58. catch (ClassNotFoundException ex) {
  59. throw new IllegalStateException(
  60. "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
  61. }
  62. def.setSource(source);
  63. beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
  64. }
  65. //工厂中没有注册internalEventListenerProcessor,则注册
  66. if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
  67. RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
  68. def.setSource(source);
  69. beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
  70. }
  71. //工厂中没有注册internalEventListenerFactory,则注册
  72. if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
  73. RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
  74. def.setSource(source);
  75. beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
  76. }
  77. return beanDefs;
  78. }

到这里也就跟踪完了。

其实还有很多种情况没有分析,只能先把握整体的脉络,遇到具体的情况再做具体分析。

总结

  • 获取标签context:component-scan上的base-package属性,有占位符的进行解析,并切分为数组形式
  • 1.配置扫描器
  • 2.利用扫描器扫描包,注册 BeanDefinition
  • 3.注册组件

——————————————————————————————————

  • 1
  • 创建一个扫描器,默认情况下会注册几个过滤器,其实就是在扫描器的 includeFilters 属性中保存几个 AnnotationTypeFilter 类型的过滤器,其中包括注解Component
  • 解析子标签context:exclude-filtercontext:exclude-filter,根据子标签上的 type 属性创建不同的类型过滤器。并添加到扫描器的 excludeFilters 属性或 includeFilters 属性中。
  • 添加其他属性等

——————————————————————————————————

  • 2
  • 遍历所有的base-package,通过base-package获取 Resource 对象数组,对符合条件的 Resource 组装成 BeanDefinition ,并将 BeanDefinition 集合返回。条件:不匹配 excludeFilters 中的过滤器,匹配 includeFilters 的过滤器的同时,如果有@Conditional注解需要满足限制。
  • 解析@Scope等注解以及元注解,设置属性
  • 包装 BeanDefinition 生成 DefinitionHolder,注册 BeanDefinition 和别名到工厂中,返回 DefinitionHolder 集合

——————————————————————————————————

  • 3
  • 新建一个扫描组件,添加标签名,并把 DefinitionHolder 集合包装后一一放入到组件中
  • 如果有没被注册的后处理器,注册到工厂后再添加到扫描组件中

Spring组件扫描--源码跟踪的更多相关文章

  1. spring security 认证源码跟踪

    spring security 认证源码跟踪 ​ 在跟踪认证源码之前,我们先根据官网说明一下security的内部原理,主要是依据一系列的filter来实现,大家可以根据https://docs.sp ...

  2. Spring组件BeanDefinition 源码解析

    BeanDefinition 继承图 继承的接口 BeanMetadataElement接口 将由承载配置源对象的bean元数据元素的类实现. 包含一个getSource的方法,可以获取到MetaDa ...

  3. spring security之 默认登录页源码跟踪

    spring security之 默认登录页源码跟踪 ​ 2021年的最后2个月,立个flag,要把Spring Security和Spring Security OAuth2的应用及主流程源码研究透 ...

  4. spring security 授权方式(自定义)及源码跟踪

    spring security 授权方式(自定义)及源码跟踪 ​ 这节我们来看看spring security的几种授权方式,及简要的源码跟踪.在初步接触spring security时,为了实现它的 ...

  5. spring security 之自定义表单登录源码跟踪

    ​ 上一节我们跟踪了security的默认登录页的源码,可以参考这里:https://www.cnblogs.com/process-h/p/15522267.html 这节我们来看看如何自定义单表认 ...

  6. Spring IOC 容器源码分析

    声明!非原创,本文出处 Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 S ...

  7. Spring IOC 容器源码分析(转)

    原文地址 Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢 ...

  8. Feign 系列(05)Spring Cloud OpenFeign 源码解析

    Feign 系列(05)Spring Cloud OpenFeign 源码解析 [TOC] Spring Cloud 系列目录(https://www.cnblogs.com/binarylei/p/ ...

  9. Spring IOC容器源码分析

    注:本文转自https://javadoop.com/post/spring-ioc Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容 ...

随机推荐

  1. Python 爬取 热词并进行分类数据分析-[热词分类+目录生成]

    日期:2020.02.04 博客期:143 星期二   [本博客的代码如若要使用,请在下方评论区留言,之后再用(就是跟我说一声)] 所有相关跳转: a.[简单准备] b.[云图制作+数据导入] c.[ ...

  2. 导出EXCEL设置单元格格式

    怎么设置导出的EXCEL文件的列格式 如何设置导出的EXCEL文件的列格式在office的EXCEL中我们可以在一个EXCEL文件中,选中一列再点击鼠标右键,选择设置单元格格式,可以将这一列设为文本格 ...

  3. php的弱类型比较

    1.==和=== ==为弱相等,也就是说12=="12" --> true,而且12=="12cdf" --> true,只取字符串中开头的整数部分 ...

  4. win10系统黑屏无法显示桌面解决

    适用情况:win10系统 黑屏无法显示出桌面但是程序能正常运行时 解决方法:win+r 调出运行窗口 运行:Explorer.exe

  5. idea没有import project解决办法

    参考:https://blog.csdn.net/zengxiaosen/article/details/52807540

  6. Java基础 -5.3

    方法的递归调用 指的是一个方法自己调用自己的情况,利用递归调用可以解决一些重复且麻烦的问题 在进行我们递归调用的时候一般要考虑如下几点问题 一定要设置方法递归调用的结束条件 每一次调用的过程之中一定要 ...

  7. IIS 应用程序池回收(代码实现)

    回收 public void StartStopRecycleApp(string appName = "项目DLL名称", string method = "Recyc ...

  8. [GWCTF 2019]mypassword

    这道题(不只这道题以后也一定)要注意控制台中的信息,给出了login.js代码,会把当前用户的用户名和密码填入表单 注册个账号,登录之后给提示不是注入题 浏览一下网站功能,feedback页面可以提交 ...

  9. 记录—JPA生成数据库表

    环境 springBoot+JPA+MySQL application-dev.yml 注意:配置中的blog数据库需要先创建,否则启动springBoot会报错 spring: #数据库连接配置 d ...

  10. linux查漏补缺-Linux文件目录结构一览表

    FHS 标准 FHS(Filesystem Hierarchy Standard),文件系统层次化标准,该标准规定了 Linux 系统中所有一级目录以及部分二级目录(/usr 和 /var)的用途. ...