SpringBoot-自动配置-源码解析,Java高级程序员面试笔记宝典

我们挨个分析。

[](

)@SpringBootConfiguration


点进去我们发现,它就是一个Configuration


@Configuration

@Indexed

public @interface SpringBootConfiguration {

    @AliasFor(

        annotation = Configuration.class

    )

    boolean proxyBeanMethods() default true;

} 

Spring中我们已经学过这个注解了,他代表当前是一个配置类,所以,在 SpringBootApplicaton中标注的@SpringBootConfiguration注解的作用就是标注此启动类是一个配置类。

[](

)@ComponentScan


从之前的Spring中我们也知道,这个注解表示IoC容器在进行注册的时候,从此注解中指定的方式进行包扫描,也不用过多纠结。

[](

)@EnableAutoConfiguration



@AutoConfigurationPackage // 通过主程序的所在的包名进行批量注册

@Import(AutoConfigurationImportSelector.class) //

public @interface EnableAutoConfiguration {



	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";



	Class[] exclude() default {};



	String[] excludeName() default {};



} 

这个注解主要由两个注解组成。我们一一分析

  • [](

)@AutoConfigurationPackage :自动配置包

```

@Import(AutoConfigurationPackages.Registrar.class) //通过主程序的所在的包名进行批量注册

public @interface AutoConfigurationPackage {

	String[] basePackages() default {};

	Class[] basePackageClasses() default {};



} 

```



我们发现,这个注解通过`@Import(AutoConfigurationPackages.Registrar.class)`给IoC容器中导入了一个组件`AutoConfigurationPackages.Registrar`



我们点进去发现,这是由连个方法组成的类,如下所示



```

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {



		@Override

		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {

			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));

		}



		@Override

		public Set determineImports(AnnotationMetadata metadata) {

			return Collections.singleton(new PackageImports(metadata));

		}



	} 

```



我们将断点打到此处,然后进行Debug进行分析。



我们发现,这个方法给容器中导入了一系列的组件



通过Debug发现,`metadata`参数代表的是最原始的那个`SpringBootApplication`启动类



![image-20210725205925975](https://img-blog.csdnimg.cn/img_convert/8791893b693b61d14d919583a84bdb51.png)



通过代码我们看到,它new了一个PackageImports对象,将启动类传进去,然后调用了getPackageNames()方法得到了一个包名,debug发现,返回的包名就是我们自己项目中的包名`cn.shaoxiongdu`,然后我们发现它将这个包名封装到了String数组中作为参数,调用了`register`方法。



所以`register`这个方法就是通过包名,进行组件的批量注册,也就是主程序类所在的包。所以这就是为什么默认的包扫描规则是主程序类所在的包。



所以注解`EnableAutoConfiguration`的第一部分,`AutoConfigurationPackage`的作用就是通过主程序的所在的包名进行批量注册,我们接下来看第二个注解。
 
  
  • [](

)@Import(AutoConfigurationImportSelector.class)

我们发现,这是一个类,点进去,发现了主要的方法如下



```

@Override

	public String[] selectImports(AnnotationMetadata annotationMetadata) {

		if (!isEnabled(annotationMetadata)) {

			return NO_IMPORTS;

		}

		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);

		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

	} 

```



通过方法名称发现这个方法返回了我们需要给容器中注册的bean名称的数组。那么我们的重点就在这里。



```

AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); //我们需要给容器中注册的bean名称的数组 

```



点进去这个方法,我们继续分析这个方法。



```

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {

		if (!isEnabled(annotationMetadata)) {

			return EMPTY_ENTRY;

		}

		AnnotationAttributes attributes = getAttributes(annotationMetadata);

		List configurations = getCandidateConfigurations(annotationMetadata, attributes); // 获取所有的需要注册的候选组件

		configurations = removeDuplicates(configurations); // 移除重复的组件

		Set exclusions = getExclusions(annotationMetadata, attributes);

		checkExcludedClasses(configurations, exclusions);

		configurations.removeAll(exclusions);

		configurations = getConfigurationClassFilter().filter(configurations);

		fireAutoConfigurationImportEvents(configurations, exclusions);

		return new AutoConfigurationEntry(configurations, exclusions);

	} 

```



通过Debug我们发现,执行到了第7行的时候`configurations`这个List中已经有了一百多个bean的名称,之后的操作就是对List集合进行一些常规处理并返回。



![image-20210725212042406](https://img-blog.csdnimg.cn/img_convert/ad35f69b13c11cd8fdf0cbb97fdac7a8.png)



所以我们只需要分析第6行这个方法`getCandidateConfigurations(annotationMetadata, attributes);`



是它返回了我们需要给容器中默认注册的bean的名称的字符数组。



我们重新Debug,进入方法



```

protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

		List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),

				getBeanClassLoader()); // 获取需要注册的组件集合

		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "

				+ "are using a custom packaging, make sure that file is correct.");

		return configurations;

	} 

总结

谈到面试,其实说白了就是刷题刷题刷题,天天作死的刷。。。。。

为了准备这个“金三银四”的春招,狂刷一个月的题,狂补超多的漏洞知识,像这次美团面试问的算法、数据库、Redis、设计模式等这些题目都是我刷到过的

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](

)**

并且我也将自己刷的题全部整理成了PDF或者Word文档(含详细答案解析)

我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...

66个Java面试知识点

架构专题(MySQL,Java,Redis,线程,并发,设计模式,Nginx,Linux,框架,微服务等)+大厂面试题详解(百度,阿里,腾讯,华为,迅雷,网易,中兴,北京中软等)

我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...

算法刷题(PDF)

是我刷到过的

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](

)**

并且我也将自己刷的题全部整理成了PDF或者Word文档(含详细答案解析)

[外链图片转存中…(img-QOyUYF27-1631182464749)]

66个Java面试知识点

架构专题(MySQL,Java,Redis,线程,并发,设计模式,Nginx,Linux,框架,微服务等)+大厂面试题详解(百度,阿里,腾讯,华为,迅雷,网易,中兴,北京中软等)

[外链图片转存中…(img-jI4AsrCy-1631182464750)]

算法刷题(PDF)

我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...

你可能感兴趣的:(程序员,java,spring,面试,后端)