Boot class
@SpringBootApplication annotation
The following three annotations are included
- SpringBootConfiguration: the boot class, the main Configuration class identified as springboot, has the function of @ Configuration annotation
- @EnableAutoConfiguration: enables automatic configuration. You can exclude classes that do not need to apply automatic configuration through the exclude property
- @ComponentScan: automatically scan and load qualified beans, and load the definitions of these beans into the spring container. By default, only the package and its sub packages of the boot class are scanned. You can specify the package to be scanned through the scanBasePackages property, which is equivalent to the basePackages property of @ ComponentScan
@Implementation principle of EnableAutoConfiguration automatic configuration
The automatic configuration of springboot is realized through the @ EnableAutoConfiguration annotation in @ SpringBootApplication,
@AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {
@EnableAutoConfiguration contains 2 comments
- @AutoConfigurationPackage: Specifies the package to apply autoconfiguration
- @Import(AutoConfigurationImportSelector.class): use @ import to collect and register bean definitions related to specific scenarios
AutoConfigurationImportSelector class
/** * Return the auto-configuration class names that should be considered. * By default: this method will load candidates using SpringFactoriesLoader with getSpringFactoriesLoaderFactoryClass(). */ protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //Call the static method loadFactoryNames() of springfactoryesloader to load List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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; }
loadFactoryNames() method of springfactoryesloader
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { //Get class loader ClassLoader classLoaderToUse = classLoader; if (classLoader == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } String factoryTypeName = factoryType.getName(); //Call the loadSpringFactories() method of the current class: use the class loader to load each META-INF/spring.factories file in the classpath return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); }
loadSpringFactories() method of SpringFactoriesLoader
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Map<String, List<String>> result = (Map)cache.get(classLoader); if (result != null) { return result; } else { HashMap result = new HashMap(); try { //Get the META-INF/spring.factories files in the classpath Enumeration urls = classLoader.getResources("META-INF/spring.factories"); //Iterate over all META-INF/spring.factories files and parse their configurations while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator(); while(var6.hasNext()) { Entry<?, ?> entry = (Entry)var6.next(); String factoryTypeName = ((String)entry.getKey()).trim(); String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); String[] var10 = factoryImplementationNames; int var11 = factoryImplementationNames.length; for(int var12 = 0; var12 < var11; ++var12) { String factoryImplementationName = var10[var12]; ((List)result.computeIfAbsent(factoryTypeName, (key) -> { return new ArrayList(); })).add(factoryImplementationName.trim()); } } } result.replaceAll((factoryType, implementations) -> { return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); }); cache.put(classLoader, result); return result; } catch (IOException var14) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14); } } }
Spring boot starter contains the dependency of spring boot autoconfigure. Spring boot autoconfigure class library provides some common automatic configurations for spring boot applications, such as jdbc, redis, mongodb, web, jpa, json, etc. The following is part of META-INF/spring.factories of spring boot autoconfigure
# AutoConfigureCache auto-configuration imports org.springframework.boot.test.autoconfigure.core.AutoConfigureCache=\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration # AutoConfigureDataCassandra auto-configuration imports org.springframework.boot.test.autoconfigure.data.cassandra.AutoConfigureDataCassandra=\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration # AutoConfigureDataJdbc auto-configuration imports org.springframework.boot.test.autoconfigure.data.jdbc.AutoConfigureDataJdbc=\ org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
key specifies the annotation, and value specifies the class to which the annotation is applied. These classes end in AutoConfiguration and are automatically configured classes.
Take an automatic configuration class org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration of JDBC as an example
@Configuration(proxyBeanMethods = false) @ConditionalOnClass({ JdbcTemplate.class, TransactionManager.class }) //Filter the configuration items conforming to the current configuration through the @ ConditionOn series annotation @AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE) @EnableConfigurationProperties(DataSourceProperties.class) public class DataSourceTransactionManagerAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnSingleCandidate(DataSource.class) static class JdbcTransactionManagerConfiguration { @Bean @ConditionalOnMissingBean(TransactionManager.class) DataSourceTransactionManager transactionManager(Environment environment, DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) { DataSourceTransactionManager transactionManager = createTransactionManager(environment, dataSource); transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager)); return transactionManager; } private DataSourceTransactionManager createTransactionManager(Environment environment, DataSource dataSource) { return environment.getProperty("spring.dao.exceptiontranslation.enabled", Boolean.class, Boolean.TRUE) ? new JdbcTransactionManager(dataSource) : new DataSourceTransactionManager(dataSource); } } }
These automatic configuration classes configure a large number of default bean s and generate instances into the spring container.
Summary: when Spring Boot is started, obtain the values specified by EnableAutoConfiguration from META-INF/spring.factories under the classpath path, and import these values into the container as automatic configuration classes.
SpringApplication.run() method
main() method of boot class
public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }
SpringApplication.run() actually calls the following method
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); }
This method does two things: instantiate SpringApplication and execute the run() method
Instantiating spring application actually calls the following methods, mainly doing four things
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)); //Infer the application type, whether it is a normal project or a web project this.webApplicationType = WebApplicationType.deduceFromClasspath(); //Gets and sets the initializer this.bootstrapRegistryInitializers = this.getBootstrapRegistryInitializersFromSpringFactories(); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //Get and set listener this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); //Infer and set the main class this.mainApplicationClass = this.deduceMainApplicationClass(); }
run() method
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); //Create parent context BootstrapContext DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); //Instantiate SpringApplicationRunListener through reflection according to the configuration file spring.factories SpringApplicationRunListeners listeners = getRunListeners(args); //Publish event listening, create a new time multicast and register the ApplicationListener obtained at the beginning with the multicast listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //Environment variables are prepared according to the type and based on the parent context ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); //Print banner Banner printedBanner = printBanner(environment); //Create application context context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); //Prepare context prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //Refresh context refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { //According to the configuration file spring.factories, instantiate the springbootexception reporter through reflection to record the exceptions during the startup of the springboot application handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { //Broadcast run events listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }
There are two contexts in springboot
1,bootstrap
- The parent context of the application is loaded before the application, and the priority is higher than the application (the properties set by the bootstrap will not be overwritten by the application)
- It is mainly used to load configurations from external sources, such as springcloud config, load configurations from the configuration center, and encrypt / decrypt configuration files
2,application
- Application context, which is mainly used for automatic configuration and spring container related operations
Execution of the run() method
springboot startup process
Preparation stage
- Configure Spring Boot Bean
- Infer application type
- Inference boot class
- Load application context initializer
Start up phase
- Run the listener to listen for Spring Boot events
- Create Spring application context
Framework initialization
Frame start
Automatic assembly