At the moment when spring cloud is popular, it is very confusing if you don’t understand the basic principles (all you see are agreements that are greater than configuration, but what about the principle? Why do you need to do this?). Spring cloud is quickly built based on spring boot. Today we will take a look at the spring boot container startup process. (This article does not explain how to quickly start spring boot, just read those directly on the official website, the official website document air tickets)
Spring boot generally specifies the container to start the main method and then start the Jar package in the command line, as shown in the figure below:
@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }Here are two things:
1. @SpringBootApplication annotation
2. SpringApplication.run() static method
Let’s explore these two contents separately below.
The source code is as follows:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {Core notes:
@SpringBootConfiguration (actually @Configuration): means that this is a JavaConfig configuration class, you can customize beans, dependencies, etc. in this class. -》This is a unique annotation for spring-boot and is commonly used.
@EnableAutoConfiguration: With the help of @Import, load all bean definitions that meet the automatic configuration criteria into the IoC container (it is recommended to be placed under the root package path, so that subpackages and classes can be scanned). -》This requires detailed digging!
@ComponentScan: Automatic scanning annotation of spring, which can define the scan range and load it into the IOC container. -》No more to say this, everyone must be familiar with the annotations of spring.
The source code of the annotation @EnableAutoConfiguration:
@SuppressWarnings("deprecation") @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {The core is an EnableAutoConfigurationImportSelector class diagram as follows:
The core method is selectedImports() in the top-level interface ImportSelector, the source code is as follows:
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } try { //1. Load 483 configuration properties from the META-INF/spring-autoconfigure-metadata.properties file (some have default values), AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata);//2. Get the annotation attribute List<String> configurations = getCandidateConfigurations(annotationMetadata,//3. Get 97 automatic configuration classes attributes); configurations = removeDuplicates(configurations);//4. Remove duplicate configurations = sort(configurations, autoConfigurationMetadata);//5. Sort Set<String> excludes = getExclusions(annotationMetadata, attributes);//6. Get checkExcludedClasses(configurations, excludes);//7. Verify the excluded class configurations.removeAll(exclusions);//8. Delete all configurations that need to be excluded = filter(configurations, autoConfigurationMetadata);//9. Filter OnClassCondition (the configured in the annotation will only take effect when a certain class exists) fireAutoConfigurationImportEvents(configurations, excclusions);//10. Trigger the automatic configuration import listening event return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } }Here are 3 core methods:
1) loadMetadata load configuration
In fact, it is to use a class loader to load: META-INF/spring-autoconfigure-metadata.properties (spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar) The configuration defined in the file, returns PropertiesAutoConfigurationMetadata (implements the AutoConfigurationMetadata interface and encapsulates the property's get set method)
2) getCandidateConfigurations Get the default supported automatic configuration class name list
Automatically configure soul method, SpringFactoriesLoader.loadFactoryNames Get the configuration of the automatic configuration class key=EnableAutoConfiguration.class from the META-INF/spring.factories (spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar) file.
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {//That's right, the two parameters here are useless...Who can explain it to me... List<String> 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; } //The return is the EnableAutoConfiguration class protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }What have you actually obtained? The spring.factories file is as follows, which actually obtains all classes of the #Auto Configure automatic configuration module.
# Initializersorg.springframework.context.ApplicationContextInitializer=/org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,/org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer# Application Listenersorg.springframework.context.ApplicationListener=/org.springframework.boot.autoconfigure.BackgroundPreinitializer# Auto Configuration Import Listenersorg.springframework.boot.autoconfigure.AutoConfigurationImportListener=/org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener# Auto Configuration Import Filtersorg.springframework.boot.autoconfigure.AutoConfigurationImportFilter=/org.springframework.boot.autoconfigure.condition.OnClassCondition# Auto Configure Here are all the automatic configuration classes org.springframework.boot.autoconfigure.EnableAutoConfiguration=/org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,/org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,/org.spr ingframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,/org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,/org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,/org.springframework.boot.autoconfigure .cassandra.CassandraAutoConfiguration,/org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,/org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,/org.springframework.boot.autoconfigure.c ontext.MessageSourceAutoConfiguration,/org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,/org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,/org.springframework.boot.autoconfigur e.dao.PersistenceExceptionTranslationAutoConfiguration,/org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,/org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,/o rg.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,/org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,/org.springframework.boot.autoconfigure.data.elasticsearch.E lasticsearchAutoConfiguration,/org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,/org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,/org.springf ramework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,/org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,/org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,/org.spr ingframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,/org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,/org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,/or g.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,/org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,/org.springframework.boot.autoconfigure.data.redis.RedisAutoConfigurati on,/org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,/org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,/org.springframework.boot.autoconfigure.data.web.SpringDataWebAu toConfiguration,/org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,/org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,/org.springframework.boot.autoconfigure.gson.GsonAutoConfigura tion,/org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,/org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,/org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,/org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,/org.spring ngframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,/org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,/org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,/o rg.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,/org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,/org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,/org.springframewor k.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,/org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,/org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,/org.springfra mework.boot.autoconfigure.jms.JmsAutoConfiguration,/org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,/org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,/org.springframework.boot.autoconfigur e.jms.activemq.ActiveMQAutoConfiguration,/org.springframework.boot.autoconfigure.jms.aremis.ArtemisAutoConfiguration,/org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,/org.springframework.boot.autoconfigure.groovy.te mplate.GroovyTemplateAutoConfiguration,/org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,/org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,/org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,/org.springframework.boot.autoconfigure.kafka.KafkaAutoConfi guration,/org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,/org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,/org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,/ org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,/org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,/org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,/org .springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,/org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,/org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAu toConfiguration,/org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,/org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,/org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, /org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,/org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,/org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,/org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,/org.spri ngframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,/org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,/org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,/org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,/org. springframework.boot.autoconfigure.session.SessionAutoConfiguration,/org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,/org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,/org.springframework.bo ot.autoconfigure.social.LinkedInAutoConfiguration,/org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,/org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,/org.springframework.boot.autoconfigure.thymeleaf .ThymeleafAutoConfiguration,/org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,/org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,/org.springframework.boot.autoconfigure.validation.V alidationAutoConfiguration,/org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,/org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,/org.springframework.boot.autoconfigure.web.E errorMvcAutoConfiguration,/org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,/org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,/org.springframework.boot.autoconfigure.web.MultipartAut oConfiguration,/org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,/org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,/org.s pringframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,/org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,/org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration# Failure analyzersorg.springframework.boot.diagnostics.FailureAnalyzer=/org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,/org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,/org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer# Template availability providersorg.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=/org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,/org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvi der,/org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,/org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,/org.springframework.boot.autoconfigure.web.JspTemplateAvailabilityProvider
3) The filter filter filters the conditions that do not meet the OnClassCondition annotation
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) { long startTime = System.nanoTime(); String[] candidates = configurations.toArray(new String[configurations.size()]); boolean[] skip = new boolean[candidates.length]; boolean skipped = false; //Get the automatic configuration import interceptor that needs to be filtered, there is only one in the spring.factories configuration: org.springframework.boot.autoconfigure.condition.OnClassCondition for (AutoConfigurationImportFilter filter: getAutoConfigurationImportFilters()) { invokeAwareMethods(filter); boolean[] match = filter.match(candidates, autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) { skip[i] = true; skipped = true; } } } if (!skipped) {//As long as there is one mismatch ->skipped = true, all matches -》skipped = false->Return directly to return configurations; } List<String> result = new ArrayList<String>(candidates.length); for (int i = 0; i < candidates.length; i++) { if (!skip[i]) {//Match-》Don't skip-》Add to result result.add(candidates[i]); } } if (logger.isTraceEnabled()) { int numberFiltered = configurations.size() - result.size(); logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms"); } return new ArrayList<String>(result); }SpringApplication.run
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args);//1. Get the listener listeners.starting();-->Start! try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners,//2. Prepare the environment and trigger the ApplicationEnvironmentPreparedEvent event applicationArguments); Banner printedBanner = printBanner(environment);//Print the startup prompt character, default spring character diagram context = createApplicationContext();//Instantiate a configurable application context analyzers = new FailureAnalyzers(context); prepareContext(context, environment, listeners, applicationArguments,//3. Prepare the context printedBanner); refreshContext(context);//4. Refresh the context afterRefresh(context, applicationArguments);//5. After refreshing the context listeners.finished(context, null);--Close! stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }1. getRunListeners Get listeners (SpringApplicationRunListeners)
It is actually the SpringApplicationRunListener class
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); } private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); } private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use Set to ensure uniqueness of strings Set<String> names = new LinkedHashSet<String>( SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 1. Load the factory name collection List<T> instances = createSpringFactoriesInstances(type, parameterTypes,// 2. Create factory instance classLoader, args, names); AnnotationAwareOrderComparator.sort(instances);// Sort return instances; }1.1 Loading factory name (loadFactoryNames)
The class loader of the current class gets the configuration of the SpringApplicationRunListener class from the META-INF/spring.factories file
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<String>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }In the above picture, after obtaining the factory class name, let’s take a look at what is defined in META-INF/spring.factories:
# PropertySource Loadersorg.springframework.boot.env.PropertySourceLoader=/org.springframework.boot.env.PropertiesPropertySourceLoader,/org.springframework.boot.env.YamlPropertySourceLoader# Run Listeners Here, look here! ! ! ! org.springframework.boot.SpringApplicationRunListener=/org.springframework.boot.context.event.EventPublishingRunListener# Application Context Initializersorg.springframework.context.ApplicationContextInitializer=/org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,/org.springframework.boot.context.ContextId ApplicationContextInitializer,/org.springframework.boot.context.config.DelegatingApplicationContextInitializer,/org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer# Application Listenersorg.springframework.context.ApplicationListener=/org.springframework.boot.ClearCachesApplicationListener,/org.springframework.boot.builder.ParentContextCloserApplicationListener,/org.springframework.boot.context.FileEncodingApplicationListener,/org.springframework.boot.context.config.AnsiOutputApplicationListener,/org.springfra mework.boot.context.config.ConfigFileApplicationListener,/org.springframework.boot.context.config.DelegatingApplicationListener,/org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,/org.springframework.boot.logging.ClasspathLoggingApplicationListener,/org.springframework.boot.logging.LoggingApplicationListener# Environment Post Processorsorg.springframework.boot.env.EnvironmentPostProcessor=/org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,/org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor# Failure Analyzersorg.springframework.boot.diagnostics.FailureAnalyzer=/org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,/org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,/org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,/org.spr ingframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,/org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,/org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,/org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer# FailureAnalysisReportersorg.springframework.boot.diagnostics.FailureAnalysisReporter=/org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
Wow, all of these classes have full names, and keys are interfaces, and values are implementation classes. We obtain the implementation class value="org.springframework.boot.SpringApplicationRunListener" query based on the key="org.springframework.boot.context.event.EventPublishingRunListener" event release and start the listener. Once you guess, you must use "reflection" to obtain the class instance based on the class name. The following is quickly verified...
1.2 Create Spring Factory Instances
Generate "EventPublishing Start Listener" factory instance based on the Set<String> names (the only implementation class EventPublishingRunListener of SpringApplicationRunListener) obtained in the first step
@SuppressWarnings("unchecked") private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<T>(names.size()); for (String name : names) { try { Class<?> instanceClass = ClassUtils.forName(name, classLoader);// Use reflection to obtain the class Assert.isAssignable(type, instanceClass); Constructor<?> constructor = instanceClass .getDeclaredConstructor(parameterTypes);// Get the constructor T instance = (T) BeanUtils.instantiateClass(constructor, args);// Construct instances based on the constructor and parameters instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; }Prepare the context
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context);//Singleton a BeanNameGenerator, set the ResourceLoader into the application context applyInitializers(context);//Execute the initializer listeners.contextPrepared(context);//Listener execution context "Prepared" method if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add spring boot special singleton bean context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // Load the resource Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[sources.size()])); listeners.contextLoaded(context);// The listener executes the "context loaded" method}Refresh the context
private void refreshContext(ConfigurableApplicationContext context) { refresh(context);//Core class if (this.registerShutdownHook) { try { context.registerShutdownHook();//Register the closing hook, execute when the container is closed} catch (AccessControlException ex) { // Not allowed in some environments. } } } protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }The final execution is the refresh method of the AbstractApplicationContext abstract class.
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //Prepare to refresh the context environment, such as preparing and verifying system properties or environment variables. prepareRefresh(); //Start the refreshBeanFactory method of the subclass. Parses xml ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //Configure container features for the BeanFactory, such as class loader, event handler, etc. prepareBeanFactory(beanFactory); try { //Set the post-processing of the BeanFactory. Empty method, leave it for subclass expansion. postProcessBeanFactory(beanFactory); //Call the postprocessors of BeanFactory, which are registered with the container in the bean definition. invokeBeanFactoryPostProcessors(beanFactory); //Register the postprocessor of Bean and call it during the bean creation process. registerBeanPostProcessors(beanFactory); //Initialize the message source in the context, that is, message bodies in different languages are processed internationally initMessageSource(); //Initialize the ApplicationEventMulticaster bean, and the application event broadcaster is initApplicationEventMulticaster(); //Initialize other special beans, empty methods, and leave them for subclass expansion. onRefresh(); //Check and register the listener Bean registerListeners(); //Instance all remaining (non-lazy-init) singleton Bean. finishBeanFactoryInitialization(beanFactory); //Publish container events and end the refresh process. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } //Destroy the created singleton Bean to avoid resource consumption. destroyBeans(); //Cancel the refresh operation and reset the active flag. cancelRefresh(ex); //Propagate exception to caller. throw ex; } finally { //Reset Spring's core cache resetCommonCaches(); } } }After refreshing the context
Spring boot provides two interfaces for users to expand themselves: ApplicationRunner and CommandLineRunner. You can perform some operations similar to data initialization after the container is started (after the context is refreshed).
private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<Object>(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());//GetAll of type ApplicationRunner from the context runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());//GetAll of type CommandLineRunner from the context AnnotationAwareOrderComparator.sort(runners);//Sorting for (Object runner : new LinkedHashSet<Object>(runners)) { if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args);//Execute} if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } }The two differences are that the parameters are different, so choose by yourself according to the actual situation.
public interface CommandLineRunner { void run(String... args) throws Exception; } public interface ApplicationRunner { void run(ApplicationArguments args) throws Exception; }The execution parameters in CommandLineRunner are the String[] args string array parameters of the original java startup class main method; the parameters in ApplicationRunner are processed to provide some methods such as:
List<String> getOptionValues(String name);
Get the value list according to the name, in the java startup command --foo=bar --foo=baz, then return list ["bar", "baz"] according to the foo parameter name
According to the previous analysis, the Spring-boot container startup process can be divided into 2 parts:
1) Execution annotation: scan beans under the specified range, load the beans corresponding to the automatic configuration class and load them into the IOC container.
2) The specific SpringAppliocation.run() in the man method runs through the SpringApplicationEvent, and there are 6 subclasses:
ApplicationFailedEvent.classApplicationPreparedEvent.classApplicationReadyEvent.classApplicationStartedEvent.classApplicationStartingEvent.classSpringApplicationEvent.class
Here we use the classic spring event-driven model, air ticket: Spring event-driven model and observer model
The class diagram is as follows:
As shown in the picture above, it is a classic spring event-driven model, including 3 roles: event publisher, event, and listener. Corresponding to spring-boot is:
1.EventPublishingRunListener This class encapsulates event publishing,
2. SpringApplicationEvent is an event defined in spring-boot (the 6 events mentioned above), inherited from ApplicationEvent (defined in spring)
3. Listener spring-boot does not implement the listener for the above 6 events (I didn't find...). Here users can implement the listener (the above 6 events) by themselves to inject the spring boot container startup process and trigger the corresponding event.
For example: Implement the ApplicationListener<ApplicationReadyEvent> interface. When the last step listener.finished is performed when the container is started, if there is no exception to start, it will be executed! You can do some data initialization and other operations.
Summarize
The above is the relevant knowledge about spring boot container startup introduced to you by the editor. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support to Wulin.com website!