赞
踩
1、main启动:
@SpringBootApplication + SpringApplication.run(App.class,args)
- @SpringBootApplication
- public class App {
- public static void main(String[] args) {
- SpringApplication.run(App.class,args);
- }
- }
spring boot分析@SpringBootApplication注解@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
1.1、@SpringBootConfiguration定义当前为配置类
1.2、@ComponentScan指定扫描哪些范围
1.3、@EnableAutoConfiguration:@AutoConfigurationPackage + @Import(AutoConfigurationImportSelector.class)
- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- @AutoConfigurationPackage
- @Import(AutoConfigurationImportSelector.class)
- public @interface EnableAutoConfiguration {
1.3.1、@AutoConfigurationPackage:@Import(AutoConfigurationPackages.Registrar.class)
new PackageImports(metadata).getPackageNames()获取主程序包名,所以spring boot默认扫描主程序所在包下所有配置注入到Bean
- 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<Object> determineImports(AnnotationMetadata metadata) {
- return Collections.singleton(new PackageImports(metadata));
- }
- }
1.3.2、 @Import(AutoConfigurationImportSelector.class)
1)、selectImports获取导入组件
- @Override
- public String[] selectImports(AnnotationMetadata annotationMetadata) {
- if (!isEnabled(annotationMetadata)) {
- return NO_IMPORTS;
- }
- AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
- return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
- }
2)、getAutoConfigurationEntry获取所有需要组件
- protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
- if (!isEnabled(annotationMetadata)) {
- return EMPTY_ENTRY;
- }
- AnnotationAttributes attributes = getAttributes(annotationMetadata);
- List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
- configurations = removeDuplicates(configurations);
- Set<String> exclusions = getExclusions(annotationMetadata, attributes);
- checkExcludedClasses(configurations, exclusions);
- configurations.removeAll(exclusions);
- configurations = getConfigurationClassFilter().filter(configurations);
- fireAutoConfigurationImportEvents(configurations, exclusions);
- return new AutoConfigurationEntry(configurations, exclusions);
- }
3)、getCandidateConfigurations获取所有要导入的候选组件
- protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
- List<String> configurations = new ArrayList<>(
- SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
- ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
- Assert.notEmpty(configurations,
- "No auto configuration classes found in META-INF/spring.factories nor 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;
- }
其中spring boot 2.7.3后已经不建议SpringFactoriesLoader.loadFactoryNames
4)、SPI机制META-INF/spring/%s.imports中的组件
- public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
- Assert.notNull(annotation, "'annotation' must not be null");
- ClassLoader classLoaderToUse = decideClassloader(classLoader);
- String location = String.format(LOCATION, annotation.getName());
- Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
- List<String> importCandidates = new ArrayList<>();
- while (urls.hasMoreElements()) {
- URL url = urls.nextElement();
- importCandidates.addAll(readCandidateConfigurations(url));
- }
- return new ImportCandidates(importCandidates);
- }
5)、EnableAutoConfiguration从META-INF/spring.factories移到org.springframework.boot.autoconfigure.AutoConfiguration.imports
分析 SpringApplication类,提供静态方法调用构造方法实现方法调用
- public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
- return run(new Class<?>[] { primarySource }, args);
- }
-
- public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
- return new SpringApplication(primarySources).run(args);
- }
- public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
- this.resourceLoader = resourceLoader;
- Assert.notNull(primarySources, "PrimarySources must not be null");
- this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
- this.webApplicationType = WebApplicationType.deduceFromClasspath();
- this.bootstrapRegistryInitializers = new ArrayList<>(
- getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
- //实例化META-INF/spring.factories 相应初始化器
- setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
- //实例化监听器
- setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
- this.mainApplicationClass = deduceMainApplicationClass();
- }
2.1、setInitializers,实例化所有初始器:
事件流程:
- # Application Context Initializers
- org.springframework.context.ApplicationContextInitializer=\
- org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
- org.springframework.boot.context.ContextIdApplicationContextInitializer,\
- org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
- org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
- org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
2.1.1、扩展:增加自定义初始化器
1)、新增自定义初始化类,实现ApplicationContextInitializer类,重写initialize方法
- public class MyInitializer implements ApplicationContextInitializer {
- @Override
- public void initialize(ConfigurableApplicationContext applicationContext) {
- System.out.println("自定义初始化执行器");
- ConfigurableEnvironment environment = applicationContext.getEnvironment();
- Map proMap = new HashMap<>();
- proMap.put("key","myinitializer");
- proMap.put("value","sk");
- environment.getPropertySources().addLast(new MapPropertySource("MyInitailizer",proMap));
- System.out.println("初始化结束,添加参数!");
- }
- }
2)、SPI配置resources/META-INF/spring.factories增加Initializers定义
- # Application Context Initializers
- org.springframework.context.ApplicationContextInitializer=\
- com.sk.cloud.spring.init.initialner.MyInitializer
3)、调试如下
4)、调用链路:SpringApplication#run()->prepareContext(..)-->applyInitializers(context)-initialize(context)-->回调自定义初始化器
2.2、setListeners,实例化所有监听器
监听机制:
事件流程:
- # Application Listeners
- org.springframework.context.ApplicationListener=\
- org.springframework.boot.ClearCachesApplicationListener,\
- org.springframework.boot.builder.ParentContextCloserApplicationListener,\
- org.springframework.boot.context.FileEncodingApplicationListener,\
- org.springframework.boot.context.config.AnsiOutputApplicationListener,\
- org.springframework.boot.context.config.DelegatingApplicationListener,\
- org.springframework.boot.context.logging.LoggingApplicationListener,\
- org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
2.2.1、扩展:增加自定义监视器(开始和结束监听器)
1)、创建自定义监听器,实现
- public class AppStartingListener implements ApplicationListener<ApplicationStartingEvent> {
-
- @Override
- public void onApplicationEvent(ApplicationStartingEvent event) {
- System.out.println("容器启动前");
- }
- }
-
-
- public class AppEndListener implements ApplicationListener<ApplicationStartedEvent> {
-
- @Override
- public void onApplicationEvent(ApplicationStartedEvent event) {
- System.out.println("容器启动后");
- }
- }
2)、SPI配置resources/META-INF/spring.factories增加Listeners定义
- # Application Listeners
- org.springframework.context.ApplicationListener=\
- com.sk.cloud.spring.init.listenter.AppEndListener,\
- com.sk.cloud.spring.init.listenter.AppStartingListener
3)、调试如下
4)、监听器回调
1)、ApplicationStartingEvent事件回调:SpringApplication#run() --> listeners.starting(..) -->回调
2)、ApplicationStartedEvent事件回调:SpringApplication#run() --> listeners.started(..) --> 回调
2.3、prepareEnvironment:准备Environment环境对象
url:Springboot配置文件加载原理及流程【源码分析】_springboot加载配置文件源码-CSDN博客
2.4、上下文刷新
1)、确定context类型
- context = createApplicationContext();
-
- public enum WebApplicationType {
- /**
- * The application should not run as a web application and should not start an
- * embedded web server.
- * 不启动内嵌的WebServer,不是运行web application
- */
- NONE,
-
- /**
- * The application should run as a servlet-based web application and should start an
- * embedded servlet web server.
- * 启动内嵌的基于servlet的web server
- */
- SERVLET,
-
- /**
- * The application should run as a reactive web application and should start an
- * embedded reactive web server.
- * 启动内嵌的reactive web server,这个application是一个reactive web application
- */
- REACTIVE;
- }
2)、prepareContext :预加载
Bean注册到单例池 --> SPI机制初始化ApplicationContextInitializer列表 --> 广播ApplicationContextInitializedEvent事件 --> 打印启动容器(Starting App ...)--> load(启动类转化为BeanDefinition注册到spring容器的BeanDefinitionMap中) --> listeners.contextLoaded(context)遍历了SpringApplication对象所有的监听器(创建SpringApplication的时候,从META-INF/spring.factories中加载到的ApplicationListener),判断实现ApplicationContextAware接口添加到spring容器的监听列表。最后广播ApplicationPreparedEvent事件添加到spring容器中
2.5、refreshContext
refreshContext(..)-->AbstractApplicationContext#refresh
- public void refresh() throws BeansException, IllegalStateException {
- //上下文刷新前的准备工作:设置启动日期、context当前状态、初始化属性和环境
- prepareRefresh();
- //获取bean工厂类
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
- //配置beanFactory一些特性,例如上下类加载器和后处理器
- prepareBeanFactory(beanFactory);
- try {
- postProcessBeanFactory(beanFactory);
-
- StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
- // 执行beanFactory后置处理器,可以自定义BeanFactoryPostProcessor修改Bean属性值
- //ConfigurationClassParser#doProcessConfigurationClass 解析所有beanDefinition(配置类、bean类)
- invokeBeanFactoryPostProcessors(beanFactory);
-
- //注册bean的PostProcessor,用于后续bean的创建和拦截:自定义BeanPostProcessor实现postProcessBeforeInitialization和postProcessAfterInitialization拦击Bean处理。例如AOP
- registerBeanPostProcessors(beanFactory);
- beanPostProcess.end();
-
- // Initialize message source for this context.
- initMessageSource();
-
- // 初始化广播器,用于发布事件
- initApplicationEventMulticaster();
-
- // 初始话context上下文特殊bean,例如tomcat容器
- onRefresh();
-
- // Check for listener beans and register them.
- registerListeners();
-
- // 实例化bean
- finishBeanFactoryInitialization(beanFactory);
-
- // Last step: publish corresponding event.
- finishRefresh();
- }
- }
以ServletWebServerFactoryAutoConfiguration配置类为例,解释一下全局配置文件中的属性如何生效,比如:server.port=8081,是如何生效的(当然不配置也会有默认值,这个默认值来自于org.apache.catalina.startup.Tomcat)
在ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性
server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。
Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。
2.1.2、启动内置tomcat
refreshContext(..)-->AbstractApplicationContext#refresh -->onRefresh() -->ServletWebServerApplicationContext#onRefresh-->createWebServer()-->getWebServerFactory()-->factory.getWebServer(..) -->getTomcatWebServer()-->initialize
1)、getWebServerFactory()
默认springboot使用tomacat容器
自动装配获取:spring-boot-autoconfigure的SPI文件中(这里注意spring boot2.7官方不推荐使用spring.factories了,EnableAutoConfiguration采用 META-INF/spring/%s.imports)
通过Import导入EmbeddedTomcat、EmbeddedJetty、EmbeddedUndertow
- @AutoConfiguration
- @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
- @ConditionalOnClass(ServletRequest.class)
- @ConditionalOnWebApplication(type = Type.SERVLET)
- @EnableConfigurationProperties(ServerProperties.class)
- @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
- ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
- ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
- ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
- public class ServletWebServerFactoryAutoConfiguration {
分析EmbeddedTomcat,条件装配存在Tomcat类装配TomcatServletWebServerFactory
- @Configuration(proxyBeanMethods = false)
- @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
- @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
- static class EmbeddedTomcat {
- @Bean
- TomcatServletWebServerFactory tomcatServletWebServerFactory(
pom文件只要依赖spring-boot-start-tomacat会将Tomcat类引入到项目中,满足EmbeddedTomcat条件装配条件,向容器注入TomcatServletWebServerFactory,springboot容器启动getWebServerFactory会获取TomcatServletWebServerFactory创建Tomcat web容器
2)、Tomacat实现类:new Tocmat并完成了一些初始化配置 --> getTomcatWebServer(创建webserver实例)并启动tomcat容器(this.tomcat.start())
- @Override
- public WebServer getWebServer(ServletContextInitializer... initializers) {
- if (this.disableMBeanRegistry) {
- Registry.disableRegistry();
- }
- Tomcat tomcat = new Tomcat();
- File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
- tomcat.setBaseDir(baseDir.getAbsolutePath());
- for (LifecycleListener listener : this.serverLifecycleListeners) {
- tomcat.getServer().addLifecycleListener(listener);
- }
- Connector connector = new Connector(this.protocol);
- connector.setThrowOnFailure(true);
- tomcat.getService().addConnector(connector);
- customizeConnector(connector);
- tomcat.setConnector(connector);
- tomcat.getHost().setAutoDeploy(false);
- configureEngine(tomcat.getEngine());
- for (Connector additionalConnector : this.additionalTomcatConnectors) {
- tomcat.getService().addConnector(additionalConnector);
- }
- prepareContext(tomcat.getHost(), initializers);
- return getTomcatWebServer(tomcat);
- }
1)、默认SpringBootBanner
printBanner(env)->bannerPrinter.print->SpringBootBanner#printBanner
- class SpringBootBanner implements Banner {
- private static final String[] BANNER = { "", " . ____ _ __ _ _",
- " /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
- " \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\__, | / / / /",
- " =========|_|==============|___/=/_/_/_/" };
-
-
- private static final String SPRING_BOOT = " :: Spring Boot :: ";
- private static final int STRAP_LINE_SIZE = 42;
- @Override
- public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
- for (String line : BANNER) {
- printStream.println(line);
- }
- String version = SpringBootVersion.getVersion();
- version = (version != null) ? " (v" + version + ")" : "";
- StringBuilder padding = new StringBuilder();
- while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
- padding.append(" ");
- }
- printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
- AnsiStyle.FAINT, version));
- printStream.println();
- }
- }
2)、自定义bannner打印
在Resources目录下新增banner.txt文件,自定义打印banner效果
2.8、Runners运行器
- private void callRunners(ApplicationContext context, ApplicationArguments args) {
- List<Object> runners = new ArrayList<>();
- runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
- runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
- AnnotationAwareOrderComparator.sort(runners);
- for (Object runner : new LinkedHashSet<>(runners)) {
- if (runner instanceof ApplicationRunner) {
- callRunner((ApplicationRunner) runner, args);
- }
- if (runner instanceof CommandLineRunner) {
- callRunner((CommandLineRunner) runner, args);
- }
- }
- }
-
- private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
- try {
- (runner).run(args);
- }
- catch (Exception ex) {
- throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
- }
- }
-
- private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
- try {
- (runner).run(args.getSourceArgs());
- }
- catch (Exception ex) {
- throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
- }
- }
调用ApplicationRunner和CommandLineRunner类执行run方法(order相同ApplicationRunner优先级更高),一般需要在初始化完毕的时候执行,例如加载数据库的配置信息
1)、自定义ApplicationRunner
- @Component
- public class MyApplicationRunner implements ApplicationRunner {
- @Override
- public void run(ApplicationArguments args) throws Exception {
- System.out.println("my application runner: init dbserver application");
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。