To undertake the former Wen springboot sentiment edify-springapplication (a), this article will be the run () method to make a detailed analysis
Springapplication#run ()
The run () method that is often called by the main function is the key to our analysis, first on the source code
Public Configurableapplicationcontext run (String ... args) {StopWatch StopWatch = new StopWatch (); Stopwatch.start (); Configurableapplicationcontext context = null; collection<springbootexceptionreporter> exceptionreporters = new arraylist<> (); Reads the java.awt.headless system variable, which defaults to true. Commonly used in Linux image rendering Configureheadlessproperty (); Get Springapplicationrunlistener Interface Set merge instantiation call public interface starting () Springapplicationrunlisteners listeners = Getrunlisteners (args); Listeners.starting (); try {applicationarguments applicationarguments = new defaultapplicationarguments (args); Environment configuration Configurableenvironment environment = prepareenvironment (listeners, applicationarguments); Spring.beaninfo.ignore Property Read Configureignorebeaninfo (Environment); Springboot Banner-like diagram Banner Printedbanner = PrintbaNner (Environment); Create a spring app context (not yet refreshed) context = CreateApplicationContext (); Springbootexceptionreporter Interface Collection Read exceptionreporters = Getspringfactoriesinstances (Sprin Gbootexceptionreporter.class, new class[] {Configurableapplicationcontext.class}, context); ApplicationContext configuration Preparecontext (context, environment, listeners, applicationarguments, Printedbanner); Refreshes the spring application context Refreshcontext (contextual); AfterRefresh (context, applicationarguments); Stopwatch.stop (); if (this.logstartupinfo) {new Startupinfologger (this.mainapplicationclass). Logstar Ted (Getapplicationlog (), stopWatch); }//Springapplicationrunlistener interface started () method call listeners.started (context); Callrunners (context, applicationarguments); } catch (Throwable ex) {handlerunfailure (context, ex, exceptionreporters, listeners); throw new IllegalStateException (ex); The running () method of the try {//Springapplicationrunlistener interface is called listeners.running (context); } catch (Throwable ex) {handlerunfailure (context, ex, exceptionreporters, NULL); throw new IllegalStateException (ex); } return context; }
The above code comments a bit more, the author block to do a list of analysis
Springapplication#getrunlisteners ()
Gets the springapplicationrunlistener interface Set Merge instantiation, according to the previous article, read is the corresponding attribute in the meta\spring.factories file,
Here I take Org.springframework.boot.context.event.EventPublishingRunListener as an example.
First observe its constructor
public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener<?> listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } }
Note the application.getlisteners () method, which, according to the previous article, will get a collection of type Applicationlistener and deposit to Simpleapplicationeventmulticaster broadcast class;
The rest of the methods, such as starting ()/started ()/environmentprepared ( ) and so on, are all corresponding events that call all Applicationlistener interfaces uniformly. The author here takes starting () as an example
@Override public void starting() { this.initialMulticaster.multicastEvent( new ApplicationStartingEvent(this.application, this.args)); }
It will look for listeners to support the response to the applicationstartingevent event and execute the appropriate event method. Response listeners are Loggingapplicationlistener and liquibaseservicelocatorapplicationlistener , etc.
Springapplication#prepareenvironment ()
Environment Environment Preparation work
private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // Create and configure the environment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 解析args参数和spring.profiles.active配置读取 configureEnvironment(environment, applicationArguments.getSourceArgs()); // 触发ApplicationEnvironmentPreparedEvent事件 listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (this.webApplicationType == WebApplicationType.NONE) { environment = new EnvironmentConverter(getClassLoader()) .convertToStandardEnvironmentIfNecessary(environment); } ConfigurationPropertySources.attach(environment); return environment; }
There is too much content in the code, the author here for their own reading to make a summary
The args parameter is wrapped as the simplecommandlinepropertysource property Source, corresponding to the keycommandLineArgs
spring.profiles.active
System property Read, configuration for different conditions
Applicationenvironmentpreparedevent event triggering, the main configfileapplicationlistener monitoring Class ( It will read the Application.properties/application.xml/application.yaml configuration file by default)
PS:Configfileapplicationlistener This class is more important, it will also go to read the configuration file in the properties of the spring.profiles.active
load profile;
Also go to read the environmentpostprocessor interface to unify the call. Interested readers can do a good bit of analysis
Binds the property source containing the environment to the configurationProperties
propertysources type of key to facilitate springboot the properties contained in the global search context
Springapplication#configureignorebeaninfo ()
Read spring.beaninfo.ignore
property, default is true, mainly for ignoring Bean's basic information
Springapplication#printbanner ()
Create a banner print object with the default print sample shown below (acting on console). Specific readers are interested in self-reading principles
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.0.3.RELEASE)
Springapplication#createapplicationcontext ()
Creates an application context object that creates the appropriate context based on the type of application that is judged.
|
context corresponds to C Lass class |
servlet |
org.springframework.boot.web.servlet.context.annotationconfigservletwebserverapplicationcontext |
servlet |
|
reactive |
|
none |
|
Obviously, all annotations are applied to load the context.
Springapplication#preparecontext ()
To prepare for a context object that has already been created
Springapplication#applyinitializers ()
Start the appropriate initialization classes, which are all implementation classes of the Applicationcontextinitializer interface
protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { // 检查相应的ApplicationContextInitializer实体类所接收的泛型实体class Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); // 只对接收的泛型为ConfigurableApplicationContext.class进行相应的初始化 Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
For the code comment above, the initialization class is basically Configurationwarningsapplicationcontextinitializer/contextidapplicationcontextinitializer /delegatingapplicationcontextinitializer/serverportinfoapplicationcontextinitializer and so on.
Interested in self-analysis of what the corresponding initialization classes are doing
Springapplication#load ()
Load beans into the appropriate context object ApplicationContext
// 此处的source一般为main函数所在的class,也可通过SpringApplication#setSource()来新增 protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug( "Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } BeanDefinitionLoader loader = createBeanDefinitionLoader( getBeanDefinitionRegistry(context), sources); if (this.beanNameGenerator != null) { loader.setBeanNameGenerator(this.beanNameGenerator); } if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } if (this.environment != null) { loader.setEnvironment(this.environment); } // 加载beans loader.load(); }
I am here most concerned about this Beandefinitionloader will play what tricks, continue down
Start with the constructor function first
Beandefinitionloader (Beandefinitionregistry registry, Object ... sources) {ASSERT.NOTNU LL (registry, "Registry must not being null"); Assert.notempty (sources, "sources must not being empty"); this.sources = sources; Annotation parsing class This.annotatedreader = new Annotatedbeandefinitionreader (registry); XML parsing class This.xmlreader = new Xmlbeandefinitionreader (registry); if (Isgroovypresent ()) {This.groovyreader = new Groovybeandefinitionreader (registry); }//Classpath scans the class and masks the specified sources class This.scanner = new Classpathbeandefinitionscanner (registry); This.scanner.addExcludeFilter (new Classexcludefilter (sources)); }
The annotatedbeandefinitionreader annotation parsing class, which registers multiple postprocessor interfaces for subsequent context refresh operations to be invoked for parsing @Configuration/@Autowired/@Required/
.
Annotatedbeandefinitionreader XML parsing class, which parses the XML configuration
classpathbeandefinitionscanner Scan the specified package in the CLASSPATH environment and specify class
And look at the processing method. load ()
public int load () {int count = 0; for (Object source:this.sources) {count + = load (source); } return count; } private int Load (Object source) {assert.notnull (source, "source must not is null"); if (source instanceof class<?>) {return load ((class<?>) source); } if (source instanceof Resource) {return load ((Resource) source); } if (source instanceof package) {Return to load (package) source; } if (source instanceof charsequence) {return load ((charsequence) source); } throw new IllegalArgumentException ("Invalid Source Type" + Source.getclass ()); }//The author focuses on private int load (class<?> source) {if (Isgroovypresent () && Groov YBeanDefinitionSource.class.isAssignableFrom (source)) {//any groovyloaders added in beans{} DSL can contribut E beans Here Groovybeandefinitionsource loader = Beanutils.instantiateclass (source, Groovybeandefinitionsource . Class); Load (loader); }//To see if the class has been @component decorated. This is used to load the main class if (Iscomponent (source)) {//Register Bean This.annotatedreaannotatedbeandefinitionrea Derder.register (source); return 1; } return 0; }
The load () method here is primarily to determine whether the set of sources classes are @Component
annotated, or inject them into the bean factory. That is, the main () function class that we write often adds @SpringApplication
annotations, which are eventually processed by Annotatedbeandefinitionreader .
Springapplication#refresh ()
Refresh the context object, the author does not expand here, can refer to the previous article Spring source sentiment edify-abstractapplicationcontext
Exception handling
Springboot exception handling mechanism is to read the Springbootexceptionreporter interface class to different exceptions for different output, interested in self-reading
Summary
Through the above analysis, the basic work principle of springboot has a certain understanding, the most important thing is that it will be the public configuration placed in the meta\spring.factories file, we will just pay more attention to this document would understand more.
As to @SpringApplication
how the annotations serve the Springboot, the author further analyzes
Springboot sentiment edify-springapplication (II.)