springboot源码解读: springboot2.4.4
# https://blog.csdn.net/qq_32828253/article/details/109496848
# https://zhuanlan.zhihu.com/p/95217578
以下所有知识均来自于网络
从main方法开始
public static void main(String[] args) {
// SpringApplication.run(AjProjectApp.class, args);
// 查看源码 发现上面 等价于
new SpringApplication(AjProjectApp.class).run(args);
}
SpringApplication 的启动就分为 初始化和运行
初始化代码
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 = new HashSet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 推断web应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 配置应用程序启动前的初始化对象
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 加载应用事件监听器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 推断应用引导类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
初始化作用: 配置基本的环境变量、资源、构造器、监听器等。 初始化阶段的主要作用是为运行SpringApplication实例对象启动环境变量准备以及进行必要的资源构造器的初始化动作
运行代码
public ConfigurableApplicationContext run(String... args) {
// 计时工具
StopWatch stopWatch = new StopWatch();
//启动计时工具
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 获取并启动监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境 application.properties配置文件会被读取
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 打印banner 就是打印spring图案
Banner printedBanner = this.printBanner(environment);
// 创建spring容器 工厂BeanFactory就是此处创建
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// spring容器前置处理
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新容器
this.refreshContext(context);
// spring容器 后置处理
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
// 发出启动结束事件
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
SpringBoot注解(自动装配的核心)
@SpringBootApplication 解读
这是一个复合注解
其中最重要的是:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
①: @SpringbootConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration # 这个是重点
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@Configuration注解标识的类中声明了1个或者多个@Bean方法,Spring容器可以使用这些方法来注入Bean,比如:
@Configuration
public class AppConfig {
//这个方法就向Spring容器注入了一个类型是MyBean名字是myBean的Bean
@Bean
public MyBean myBean() {
// instantiate, configure and return bean ...
}
}
2. @EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //自动配置包
@Import({AutoConfigurationImportSelector.class}) //自动配置导入选择
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class>[] exclude() default {};
String[] excludeName() default {};
}
@Import(AutoConfigurationImportSelector.class)它帮我们导入了AutoConfigurationImportSelector,这个类中存在一个方法可以帮我们获取所有的配置
当我们的SpringBoot项目启动的时候,会先导入AutoConfigurationImportSelector,这个类会帮我们选择所有候选的配置,我们需要导入的配置都是SpringBoot帮我们写好的一个一个的配置类,那么这些配置类的位置,存在与META-INF/spring.factories文件中,通过这个文件,Spring可以找到这些配置类的位置,于是去加载其中的配置。
3. @ComponentScan
@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中, @ComponentScan注解默认就会装配标识了@Controller,@Service,@Repository,@Component注解的类到spring容器中