1.引导类注解@SpringBootApplication 是一个组合注解
里面有
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
@Documented
作用:表明该注解应被包含在 JavaDoc 中。 使用场景:通常用于元注解(如 @SpringBootApplication),表示其子类也应被文档化。
@Inherited
作用:允许子类继承父类的注解。 示例:如果父类被 @SpringBootApplication 标注,子类默认也会继承该注解的配置。
另外三个是重要注解
@SpringBootConfiguration
- 底层就是一个@Configuration,表示当前引导类就是一个配置类,用于定义 Bean。
@componentSan
组件扫描,扫描当前包及其子包下的组件(如 @Component, @Service, @Controller 等),使其能够被Spring识别
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
@Filter 是 Spring 中用于 定义组件扫描过滤规则 的注解,通常配合@ComponentSan的 includeFilters 或 excludeFilters 属性使用,用于精确控制哪些组件需要被扫描或排除的Spring 管理的 Bean。
包含特定组件(includeFilters):只扫描符合条件的类。
排除特定组件(excludeFilters):跳过不符合条件的类。
灵活匹配规则:支持按注解、类名、正则表达式、AspectJ 表达式或自定义逻辑过滤。
@EnableAutoConfiguration
是一个组合注解,由两个注解构成
@AutoConfigUrationPackage
该类会自动去调用registerBeanDefinitions方法,该方法中能够获取到引导类所在的包,配置@ComponentScan就可以让SpringBoot去扫描引导类包下的组件
@import
该注解导入一个AutoConfigurationImportSelector类,该类会自动调用selectImports方法,方法内部会调用getAutoConfigurationEntry方法,这个方法内部又会调用getCandidateConfigurations方法最终调用了SpringFactoriesLoader这个方法传入的参数(AutoConfiguration.class)获取并构建构建资源路径:META-INF/spring/<注解全限定名>.imports,然后通过findUrlsInClasspath方法 在类路径下查找所有匹配的 URL 资源,遍历后返回一个字符串集合,然后经过排除,判断,过滤,继续返回,然后转化为字符串数组返回.
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
//selectImports`方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationEntry autoConfigurationEntry =
// getAutoConfigurationEntry方法
this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
//去重
configurations = this.removeDuplicates(configurations);
//获取需要排除的配置类
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
//检查排除的配置类是否有不存在的
this.checkExcludedClasses(configurations, exclusions);
//去除需要排除的类
configurations.removeAll(exclusions);
// 应用自动配置类过滤器(基于 @Conditional 条件进一步筛选)
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
}
`
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//load方法
List<String> configurations = ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).getCandidates();
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
Assert.notNull(annotation, "'annotation' must not be null");
ClassLoader classLoaderToUse = decideClassloader(classLoader);
//获取并构建构建资源路径:`META-INF/spring/<注解全限定名>.imports,
String location = String.format("META-INF/spring/%s.imports", annotation.getName());
//在类路径下查找所有匹配的 URL 资源
Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
List<String> importCandidates = new ArrayList();
//遍历
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
//存入集合
importCandidates.addAll(readCandidateConfigurations(url));
}
return new ImportCandidates(importCandidates);
}
2、一个方法 SpringApplication.run(引导类.class, args);
底层就是(new SpringApplication(primarySources)).run(args)
-
构造器【赋值操作】
- new SpringApplication(primarySources)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.sources = new LinkedHashSet(); this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; this.addCommandLineProperties = true; this.addConversionService = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = Collections.emptySet(); this.isCustomEnvironment = false; this.lazyInitialization = false; this.applicationContextFactory = ApplicationContextFactory.DEFAULT; this.applicationStartup = ApplicationStartup.DEFAULT; this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); //判断有没有Servlet环境 this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); //把 spring.factories 文件中key为ApplicationContextInitializer的内容加载进内存 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //把 spring.factories 文件中key为ApplicationListener的内容加载进内存 this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); //判断引导类是否有一个main方法 this.mainApplicationClass = this.deduceMainApplicationClass(); } -
run方法
public ConfigurableApplicationContext run(String... args) { long startTime = System.nanoTime(); DefaultBootstrapContext bootstrapContext = this.createBootstrapContext(); ConfigurableApplicationContext context = null; this.configureHeadlessProperty(); //封装之前构造器加载进内存监听器为SpringApplicationRunListeners SpringApplicationRunListeners listeners = this.getRunListeners(args); //开启监听器 listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //预处理环境 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments); this.configureIgnoreBeanInfo(environment); //打印Logo Banner printedBanner = this.printBanner(environment); //创建容器 context = this.createApplicationContext(); context.setApplicationStartup(this.applicationStartup); //预解析spring容器 this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //初始化spring容器 this.refreshContext(context); this.afterRefresh(context, applicationArguments); //统计启动时间 Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup); } //开启监听器 listeners.started(context, timeTakenToStartup); //回调接口,应用运行器,命令行运行器 this.callRunners(context, applicationArguments); } catch (Throwable var12) { this.handleRunFailure(context, var12, listeners); throw new IllegalStateException(var12); } try { Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); listeners.ready(context, timeTakenToReady); return context; } catch (Throwable var11) { this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null); throw new IllegalStateException(var11); } }
run方法会去读取@EnableAutoConfigurationl加载进内存的字符串数组,通过反射创建实例,最终作为Bean并注入到Spring容器中