• 面试官:ThreadLocal使用场景有哪些?内存泄露问题如何避免?


    SpringBoot自动配置原理是什么?

    面试过程中问得最多的可能是自动装配的原理,而自动装配是在启动过程中完成,只不过在刚开始的时候我们选择性的跳过了,下面详细讲解自动装配的过程。

    1、在springboot的启动过程中,有一个步骤是创建上下文,如果不记得可以看下面的代码:

    1. public ConfigurableApplicationContext run(String... args) {
    2. StopWatch stopWatch = new StopWatch();
    3. stopWatch.start();
    4. ConfigurableApplicationContext context = null;
    5. Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    6. configureHeadlessProperty();
    7. SpringApplicationRunListeners listeners = getRunListeners(args);
    8. listeners.starting();
    9. try {
    10. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    11. ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    12. configureIgnoreBeanInfo(environment);
    13. Banner printedBanner = printBanner(environment);
    14. context = createApplicationContext();
    15. exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    16. new Class[] { ConfigurableApplicationContext.class }, context);
    17. //此处完成自动装配的过程
    18. prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    19. refreshContext(context);
    20. afterRefresh(context, applicationArguments);
    21. stopWatch.stop();
    22. if (this.logStartupInfo) {
    23. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    24. }
    25. listeners.started(context);
    26. callRunners(context, applicationArguments);
    27. }
    28. catch (Throwable ex) {
    29. handleRunFailure(context, ex, exceptionReporters, listeners);
    30. throw new IllegalStateException(ex);
    31. }
    32. try {
    33. listeners.running(context);
    34. }
    35. catch (Throwable ex) {
    36. handleRunFailure(context, ex, exceptionReporters, null);
    37. throw new IllegalStateException(ex);
    38. }
    39. return context;
    40. }

    2、在prepareContext方法中查找load方法,一层一层向内点击,找到最终的load方法

    1. //prepareContext方法
    2. private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
    3. SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    4. context.setEnvironment(environment);
    5. postProcessApplicationContext(context);
    6. applyInitializers(context);
    7. listeners.contextPrepared(context);
    8. if (this.logStartupInfo) {
    9. logStartupInfo(context.getParent() == null);
    10. logStartupProfileInfo(context);
    11. }
    12. // Add boot specific singleton beans
    13. ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    14. beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    15. if (printedBanner != null) {
    16. beanFactory.registerSingleton("springBootBanner", printedBanner);
    17. }
    18. if (beanFactory instanceof DefaultListableBeanFactory) {
    19. ((DefaultListableBeanFactory) beanFactory)
    20. .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    21. }
    22. if (this.lazyInitialization) {
    23. context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    24. }
    25. // Load the sources
    26. Set<Object> sources = getAllSources();
    27. Assert.notEmpty(sources, "Sources must not be empty");
    28. //load方法完成该功能
    29. load(context, sources.toArray(new Object[0]));
    30. listeners.contextLoaded(context);
    31. }
    32. /**
    33. * Load beans into the application context.
    34. * @param context the context to load beans into
    35. * @param sources the sources to load
    36. * 加载bean对象到context中
    37. */
    38. protected void load(ApplicationContext context, Object[] sources) {
    39. if (logger.isDebugEnabled()) {
    40. logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    41. }
    42. //获取bean对象定义的加载器
    43. BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    44. if (this.beanNameGenerator != null) {
    45. loader.setBeanNameGenerator(this.beanNameGenerator);
    46. }
    47. if (this.resourceLoader != null) {
    48. loader.setResourceLoader(this.resourceLoader);
    49. }
    50. if (this.environment != null) {
    51. loader.setEnvironment(this.environment);
    52. }
    53. loader.load();
    54. }
    55. /**
    56. * Load the sources into the reader.
    57. * @return the number of loaded beans
    58. */
    59. int load() {
    60. int count = 0;
    61. for (Object source : this.sources) {
    62. count += load(source);
    63. }
    64. return count;
    65. }

    3、实际执行load的是BeanDefinitionLoader中的load方法,如下:

    1. //实际记载bean的方法
    2. private int load(Object source) {
    3. Assert.notNull(source, "Source must not be null");
    4. //如果是class类型,启用注解类型
    5. if (source instanceof Class<?>) {
    6. return load((Class<?>) source);
    7. }
    8. //如果是resource类型,启动xml解析
    9. if (source instanceof Resource) {
    10. return load((Resource) source);
    11. }
    12. //如果是package类型,启用扫描包,例如@ComponentScan
    13. if (source instanceof Package) {
    14. return load((Package) source);
    15. }
    16. //如果是字符串类型,直接加载
    17. if (source instanceof CharSequence) {
    18. return load((CharSequence) source);
    19. }
    20. throw new IllegalArgumentException("Invalid source type " + source.getClass());
    21. }

    4、下面方法将用来判断是否资源的类型,是使用groovy加载还是使用注解的方式

    1. private int load(Class<?> source) {
    2. //判断使用groovy脚本
    3. if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
    4. // Any GroovyLoaders added in beans{} DSL can contribute beans here
    5. GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
    6. load(loader);
    7. }
    8. //使用注解加载
    9. if (isComponent(source)) {
    10. this.annotatedReader.register(source);
    11. return 1;
    12. }
    13. return 0;
    14. }

    5、下面方法判断启动类中是否包含@Component注解,但是会神奇的发现我们的启动类中并没有该注解,继续更进发现MergedAnnotations类传入了一个参数
    SearchStrategy.TYPE_HIERARCHY,会查找继承关系中是否包含这个注解,@SpringBootApplication-->@SpringBootConfiguration-->@Configuration-->@Component,当找到@Component注解之后,会把该对象注册到AnnotatedBeanDefinitionReader对象中

    1. private boolean isComponent(Class<?> type) {
    2. // This has to be a bit of a guess. The only way to be sure that this type is
    3. // eligible is to make a bean definition out of it and try to instantiate it.
    4. if (MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).isPresent(Component.class)) {
    5. return true;
    6. }
    7. // Nested anonymous classes are not eligible for registration, nor are groovy
    8. // closures
    9. return !type.getName().matches(".*\\$_.*closure.*") && !type.isAnonymousClass()
    10. && type.getConstructors() != null && type.getConstructors().length != 0;
    11. }
    12. /**
    13. * Register a bean from the given bean class, deriving its metadata from
    14. * class-declared annotations.
    15. * 从给定的bean class中注册一个bean对象,从注解中找到相关的元数据
    16. */
    17. private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
    18. @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
    19. @Nullable BeanDefinitionCustomizer[] customizers) {
    20. AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    21. if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    22. return;
    23. }
    24. abd.setInstanceSupplier(supplier);
    25. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    26. abd.setScope(scopeMetadata.getScopeName());
    27. String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    28. AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    29. if (qualifiers != null) {
    30. for (Class<? extends Annotation> qualifier : qualifiers) {
    31. if (Primary.class == qualifier) {
    32. abd.setPrimary(true);
    33. }
    34. else if (Lazy.class == qualifier) {
    35. abd.setLazyInit(true);
    36. }
    37. else {
    38. abd.addQualifier(new AutowireCandidateQualifier(qualifier));
    39. }
    40. }
    41. }
    42. if (customizers != null) {
    43. for (BeanDefinitionCustomizer customizer : customizers) {
    44. customizer.customize(abd);
    45. }
    46. }
    47. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    48. definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    49. BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    50. }
    51. /**
    52. * Register the given bean definition with the given bean factory.
    53. * 注册主类,如果有别名可以设置别名
    54. */
    55. public static void registerBeanDefinition(
    56. BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    57. throws BeanDefinitionStoreException {
    58. // Register bean definition under primary name.
    59. String beanName = definitionHolder.getBeanName();
    60. registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    61. // Register aliases for bean name, if any.
    62. String[] aliases = definitionHolder.getAliases();
    63. if (aliases != null) {
    64. for (String alias : aliases) {
    65. registry.registerAlias(beanName, alias);
    66. }
    67. }
    68. }
    69. //@SpringBootApplication
    70. @Target(ElementType.TYPE)
    71. @Retention(RetentionPolicy.RUNTIME)
    72. @Documented
    73. @Inherited
    74. @SpringBootConfiguration
    75. @EnableAutoConfiguration
    76. @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    77. @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    78. public @interface SpringBootApplication {}
    79. //@SpringBootConfiguration
    80. @Target(ElementType.TYPE)
    81. @Retention(RetentionPolicy.RUNTIME)
    82. @Documented
    83. @Configuration
    84. public @interface SpringBootConfiguration {}
    85. //@Configuration
    86. @Target(ElementType.TYPE)
    87. @Retention(RetentionPolicy.RUNTIME)
    88. @Documented
    89. @Component
    90. public @interface Configuration {}

    当看完上述代码之后,只是完成了启动对象的注入,自动装配还没有开始,下面开始进入到自动装配。

    6、自动装配入口,从刷新容器开始

    1. @Override
    2. public void refresh() throws BeansException, IllegalStateException {
    3. synchronized (this.startupShutdownMonitor) {
    4. // Prepare this context for refreshing.
    5. prepareRefresh();
    6. // Tell the subclass to refresh the internal bean factory.
    7. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    8. // Prepare the bean factory for use in this context.
    9. prepareBeanFactory(beanFactory);
    10. try {
    11. // Allows post-processing of the bean factory in context subclasses.
    12. postProcessBeanFactory(beanFactory);
    13. // Invoke factory processors registered as beans in the context.
    14. // 此处是自动装配的入口
    15. invokeBeanFactoryPostProcessors(beanFactory);
    16. }

    7、在
    invokeBeanFactoryPostProcessors方法中完成bean的实例化和执行

    1. /**
    2. * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
    3. * respecting explicit order if given.
    4. * <p>Must be called before singleton instantiation.
    5. */
    6. protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    7. //开始执行beanFactoryPostProcessor对应实现类,需要知道的是beanFactoryPostProcessor是spring的扩展接口,在刷新容器之前,该接口可以用来修改bean元数据信息
    8. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    9. // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    10. // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    11. if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    12. beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    13. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    14. }
    15. }

    8、查看
    invokeBeanFactoryPostProcessors的具体执行方法

    1. public static void invokeBeanFactoryPostProcessors(
    2. ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    3. // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    4. Set<String> processedBeans = new HashSet<>();
    5. if (beanFactory instanceof BeanDefinitionRegistry) {
    6. BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
    7. List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
    8. List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
    9. //开始遍历三个内部类,如果属于BeanDefinitionRegistryPostProcessor子类,加入到bean注册的集合,否则加入到regularPostProcessors
    10. for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
    11. if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
    12. BeanDefinitionRegistryPostProcessor registryProcessor =
    13. (BeanDefinitionRegistryPostProcessor) postProcessor;
    14. registryProcessor.postProcessBeanDefinitionRegistry(registry);
    15. registryProcessors.add(registryProcessor);
    16. }
    17. else {
    18. regularPostProcessors.add(postProcessor);
    19. }
    20. }
    21. // Do not initialize FactoryBeans here: We need to leave all regular beans
    22. // uninitialized to let the bean factory post-processors apply to them!
    23. // Separate between BeanDefinitionRegistryPostProcessors that implement
    24. // PriorityOrdered, Ordered, and the rest.
    25. List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
    26. // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
    27. //通过BeanDefinitionRegistryPostProcessor获取到对应的处理类“org.springframework.context.annotation.internalConfigurationAnnotationProcessor”,但是需要注意的是这个类在springboot中搜索不到,这个类的完全限定名在AnnotationConfigEmbeddedWebApplicationContext中,在进行初始化的时候会装配几个类,在创建AnnotatedBeanDefinitionReader对象的时候会将该类注册到bean对象中,此处可以看到internalConfigurationAnnotationProcessor为bean名称,容器中真正的类是ConfigurationClassPostProcessor
    28. String[] postProcessorNames =
    29. beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    30. //首先执行类型为PriorityOrdered的BeanDefinitionRegistryPostProcessor
    31. //PriorityOrdered类型表明为优先执行
    32. for (String ppName : postProcessorNames) {
    33. if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    34. //获取对应的bean
    35. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    36. //用来存储已经执行过的BeanDefinitionRegistryPostProcessor
    37. processedBeans.add(ppName);
    38. }
    39. }
    40. sortPostProcessors(currentRegistryProcessors, beanFactory);
    41. registryProcessors.addAll(currentRegistryProcessors);
    42. //开始执行装配逻辑
    43. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    44. currentRegistryProcessors.clear();
    45. // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
    46. //其次执行类型为Ordered的BeanDefinitionRegistryPostProcessor
    47. //Ordered表明按顺序执行
    48. postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    49. for (String ppName : postProcessorNames) {
    50. if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
    51. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    52. processedBeans.add(ppName);
    53. }
    54. }
    55. sortPostProcessors(currentRegistryProcessors, beanFactory);
    56. registryProcessors.addAll(currentRegistryProcessors);
    57. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    58. currentRegistryProcessors.clear();
    59. // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
    60. //循环中执行类型不为PriorityOrdered,Ordered类型的BeanDefinitionRegistryPostProcessor
    61. boolean reiterate = true;
    62. while (reiterate) {
    63. reiterate = false;
    64. postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    65. for (String ppName : postProcessorNames) {
    66. if (!processedBeans.contains(ppName)) {
    67. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    68. processedBeans.add(ppName);
    69. reiterate = true;
    70. }
    71. }
    72. sortPostProcessors(currentRegistryProcessors, beanFactory);
    73. registryProcessors.addAll(currentRegistryProcessors);
    74. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    75. currentRegistryProcessors.clear();
    76. }
    77. // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
    78. //执行父类方法,优先执行注册处理类
    79. invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
    80. //执行有规则处理类
    81. invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    82. }
    83. else {
    84. // Invoke factory processors registered with the context instance.
    85. invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    86. }
    87. // Do not initialize FactoryBeans here: We need to leave all regular beans
    88. // uninitialized to let the bean factory post-processors apply to them!
    89. String[] postProcessorNames =
    90. beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    91. // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    92. // Ordered, and the rest.
    93. List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    94. List<String> orderedPostProcessorNames = new ArrayList<>();
    95. List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    96. for (String ppName : postProcessorNames) {
    97. if (processedBeans.contains(ppName)) {
    98. // skip - already processed in first phase above
    99. }
    100. else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    101. priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    102. }
    103. else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    104. orderedPostProcessorNames.add(ppName);
    105. }
    106. else {
    107. nonOrderedPostProcessorNames.add(ppName);
    108. }
    109. }
    110. // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
    111. sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    112. invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    113. // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
    114. List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
    115. for (String postProcessorName : orderedPostProcessorNames) {
    116. orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    117. }
    118. sortPostProcessors(orderedPostProcessors, beanFactory);
    119. invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
    120. // Finally, invoke all other BeanFactoryPostProcessors.
    121. List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    122. for (String postProcessorName : nonOrderedPostProcessorNames) {
    123. nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    124. }
    125. invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    126. // Clear cached merged bean definitions since the post-processors might have
    127. // modified the original metadata, e.g. replacing placeholders in values...
    128. beanFactory.clearMetadataCache();
    129. }

    9、开始执行自动配置逻辑(启动类指定的配置,非默认配置),可以通过debug的方式一层层向里进行查找,会发现最终会在ConfigurationClassParser类中,此类是所有配置类的解析类,所有的解析逻辑在parser.parse(candidates)中

    1. public void parse(Set<BeanDefinitionHolder> configCandidates) {
    2. for (BeanDefinitionHolder holder : configCandidates) {
    3. BeanDefinition bd = holder.getBeanDefinition();
    4. try {
    5. //是否是注解类
    6. if (bd instanceof AnnotatedBeanDefinition) {
    7. parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
    8. }
    9. else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
    10. parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
    11. }
    12. else {
    13. parse(bd.getBeanClassName(), holder.getBeanName());
    14. }
    15. }
    16. catch (BeanDefinitionStoreException ex) {
    17. throw ex;
    18. }
    19. catch (Throwable ex) {
    20. throw new BeanDefinitionStoreException(
    21. "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
    22. }
    23. }
    24. //执行配置类
    25. this.deferredImportSelectorHandler.process();
    26. }
    27. -------------------
    28. protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    29. processConfigurationClass(new ConfigurationClass(metadata, beanName));
    30. }
    31. -------------------
    32. protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    33. if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
    34. return;
    35. }
    36. ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    37. if (existingClass != null) {
    38. if (configClass.isImported()) {
    39. if (existingClass.isImported()) {
    40. existingClass.mergeImportedBy(configClass);
    41. }
    42. // Otherwise ignore new imported config class; existing non-imported class overrides it.
    43. return;
    44. }
    45. else {
    46. // Explicit bean definition found, probably replacing an import.
    47. // Let's remove the old one and go with the new one.
    48. this.configurationClasses.remove(configClass);
    49. this.knownSuperclasses.values().removeIf(configClass::equals);
    50. }
    51. }
    52. // Recursively process the configuration class and its superclass hierarchy.
    53. SourceClass sourceClass = asSourceClass(configClass);
    54. do {
    55. //循环处理bean,如果有父类,则处理父类,直至结束
    56. sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    57. }
    58. while (sourceClass != null);
    59. this.configurationClasses.put(configClass, configClass);
    60. }

    10、继续跟进
    doProcessConfigurationClass方法,此方式是支持注解配置的核心逻辑

    1. /**
    2. * Apply processing and build a complete {@link ConfigurationClass} by reading the
    3. * annotations, members and methods from the source class. This method can be called
    4. * multiple times as relevant sources are discovered.
    5. * @param configClass the configuration class being build
    6. * @param sourceClass a source class
    7. * @return the superclass, or {@code null} if none found or previously processed
    8. */
    9. @Nullable
    10. protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
    11. throws IOException {
    12. //处理内部类逻辑,由于传来的参数是启动类,并不包含内部类,所以跳过
    13. if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
    14. // Recursively process any member (nested) classes first
    15. processMemberClasses(configClass, sourceClass);
    16. }
    17. // Process any @PropertySource annotations
    18. //针对属性配置的解析
    19. for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
    20. sourceClass.getMetadata(), PropertySources.class,
    21. org.springframework.context.annotation.PropertySource.class)) {
    22. if (this.environment instanceof ConfigurableEnvironment) {
    23. processPropertySource(propertySource);
    24. }
    25. else {
    26. logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
    27. "]. Reason: Environment must implement ConfigurableEnvironment");
    28. }
    29. }
    30. // Process any @ComponentScan annotations
    31. // 这里是根据启动类@ComponentScan注解来扫描项目中的bean
    32. Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
    33. sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    34. if (!componentScans.isEmpty() &&
    35. !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
    36. for (AnnotationAttributes componentScan : componentScans) {
    37. // The config class is annotated with @ComponentScan -> perform the scan immediately
    38. //遍历项目中的bean,如果是注解定义的bean,则进一步解析
    39. Set<BeanDefinitionHolder> scannedBeanDefinitions =
    40. this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
    41. // Check the set of scanned definitions for any further config classes and parse recursively if needed
    42. for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
    43. BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
    44. if (bdCand == null) {
    45. bdCand = holder.getBeanDefinition();
    46. }
    47. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
    48. //递归解析,所有的bean,如果有注解,会进一步解析注解中包含的bean
    49. parse(bdCand.getBeanClassName(), holder.getBeanName());
    50. }
    51. }
    52. }
    53. }
    54. // Process any @Import annotations
    55. //递归解析,获取导入的配置类,很多情况下,导入的配置类中会同样包含导入类注解
    56. processImports(configClass, sourceClass, getImports(sourceClass), true);
    57. // Process any @ImportResource annotations
    58. //解析@ImportResource配置类
    59. AnnotationAttributes importResource =
    60. AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
    61. if (importResource != null) {
    62. String[] resources = importResource.getStringArray("locations");
    63. Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
    64. for (String resource : resources) {
    65. String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
    66. configClass.addImportedResource(resolvedResource, readerClass);
    67. }
    68. }
    69. // Process individual @Bean methods
    70. //处理@Bean注解修饰的类
    71. Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    72. for (MethodMetadata methodMetadata : beanMethods) {
    73. configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    74. }
    75. // Process default methods on interfaces
    76. // 处理接口中的默认方法
    77. processInterfaces(configClass, sourceClass);
    78. // Process superclass, if any
    79. //如果该类有父类,则继续返回,上层方法判断不为空,则继续递归执行
    80. if (sourceClass.getMetadata().hasSuperClass()) {
    81. String superclass = sourceClass.getMetadata().getSuperClassName();
    82. if (superclass != null && !superclass.startsWith("java") &&
    83. !this.knownSuperclasses.containsKey(superclass)) {
    84. this.knownSuperclasses.put(superclass, configClass);
    85. // Superclass found, return its annotation metadata and recurse
    86. return sourceClass.getSuperClass();
    87. }
    88. }
    89. // No superclass -> processing is complete
    90. return null;
    91. }

    11、查看获取配置类的逻辑

    1. processImports(configClass, sourceClass, getImports(sourceClass), true);
    2. /**
    3. * Returns {@code @Import} class, considering all meta-annotations.
    4. */
    5. private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
    6. Set<SourceClass> imports = new LinkedHashSet<>();
    7. Set<SourceClass> visited = new LinkedHashSet<>();
    8. collectImports(sourceClass, imports, visited);
    9. return imports;
    10. }
    11. ------------------
    12. /**
    13. * Recursively collect all declared {@code @Import} values. Unlike most
    14. * meta-annotations it is valid to have several {@code @Import}s declared with
    15. * different values; the usual process of returning values from the first
    16. * meta-annotation on a class is not sufficient.
    17. * <p>For example, it is common for a {@code @Configuration} class to declare direct
    18. * {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
    19. * annotation.
    20. * 看到所有的bean都以导入的方式被加载进去
    21. */
    22. private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
    23. throws IOException {
    24. if (visited.add(sourceClass)) {
    25. for (SourceClass annotation : sourceClass.getAnnotations()) {
    26. String annName = annotation.getMetadata().getClassName();
    27. if (!annName.equals(Import.class.getName())) {
    28. collectImports(annotation, imports, visited);
    29. }
    30. }
    31. imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
    32. }
    33. }

    12、继续回到ConfigurationClassParser中的parse方法中的最后一行,继续跟进该方法:

    1. this.deferredImportSelectorHandler.process()
    2. -------------
    3. public void process() {
    4. List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    5. this.deferredImportSelectors = null;
    6. try {
    7. if (deferredImports != null) {
    8. DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
    9. deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
    10. deferredImports.forEach(handler::register);
    11. handler.processGroupImports();
    12. }
    13. }
    14. finally {
    15. this.deferredImportSelectors = new ArrayList<>();
    16. }
    17. }
    18. ---------------
    19. public void processGroupImports() {
    20. for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
    21. grouping.getImports().forEach(entry -> {
    22. ConfigurationClass configurationClass = this.configurationClasses.get(
    23. entry.getMetadata());
    24. try {
    25. processImports(configurationClass, asSourceClass(configurationClass),
    26. asSourceClasses(entry.getImportClassName()), false);
    27. }
    28. catch (BeanDefinitionStoreException ex) {
    29. throw ex;
    30. }
    31. catch (Throwable ex) {
    32. throw new BeanDefinitionStoreException(
    33. "Failed to process import candidates for configuration class [" +
    34. configurationClass.getMetadata().getClassName() + "]", ex);
    35. }
    36. });
    37. }
    38. }
    39. ------------
    40. /**
    41. * Return the imports defined by the group.
    42. * @return each import with its associated configuration class
    43. */
    44. public Iterable<Group.Entry> getImports() {
    45. for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
    46. this.group.process(deferredImport.getConfigurationClass().getMetadata(),
    47. deferredImport.getImportSelector());
    48. }
    49. return this.group.selectImports();
    50. }
    51. }
    52. ------------
    53. public DeferredImportSelector getImportSelector() {
    54. return this.importSelector;
    55. }
    56. ------------
    57. @Override
    58. public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
    59. Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
    60. () -> String.format("Only %s implementations are supported, got %s",
    61. AutoConfigurationImportSelector.class.getSimpleName(),
    62. deferredImportSelector.getClass().getName()));
    63. AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
    64. .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
    65. this.autoConfigurationEntries.add(autoConfigurationEntry);
    66. for (String importClassName : autoConfigurationEntry.getConfigurations()) {
    67. this.entries.putIfAbsent(importClassName, annotationMetadata);
    68. }
    69. }

    如何理解springboot中的starter?

    使用spring+springmvc框架进行开发的时候,如果需要引入mybatis框架,那么需要在xml中定义需要的bean对象,这个过程很明显是很麻烦的,如果需要引入额外的其他组件,那么也需要进行复杂的配置,因此在springboot中引入了starter

    starter就是一个jar包,写一个@Configuration的配置类,将这些bean定义在其中,然后再starter包的META-INF/spring.factories中写入配置类,那么springboot程序在启动的时候就会按照约定来加载该配置类

    开发人员只需要将相应的starter包依赖进应用中,进行相关的属性配置,就可以进行代码开发,而不需要单独进行bean对象的配置

     

  • 相关阅读:
    Linux系统启动过程---目录结构---文件系统超详解析
    css设置z-index为无穷大
    算法(三)
    Elasticsearch安装
    CS231n-2022 Module1: Minimal Neural Network case study
    Redis:分布式锁误删原因分析
    Java学习到面试所遇的小小问题
    LM小型可编程控制器软件(基于CoDeSys)笔记二十九:查看
    jquery的使用
    OW-DETR | 基于 Transformer 的开放世界目标检测器
  • 原文地址:https://blog.csdn.net/m0_71777195/article/details/125540320