Preliminary study on principle
pom.xml
Parent dependency
It mainly depends on a parent project, which mainly manages the resource filtering and plug-ins of the project!
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
Click in and find another parent dependency
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.5.RELEASE</version> <relativePath>../../spring-boot-dependencies</relativePath> </parent>
This is the place to really manage all dependent versions in the SpringBoot application, the SpringBoot version control center
In the future, we will import dependency. By default, we don't need to write a version; However, if the imported package is not managed in the dependency, you need to manually configure the version
Launcher spring boot starter
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
Springboot boot starter XXX: the scenario initiator of spring boot
Spring boot starter Web: it helps us import the components that the web module depends on for normal operation;
SpringBoot extracts all functional scenarios and makes them into starters. You only need to introduce these starters into the project, and all related dependencies will be imported. We can import the scenario starters with what functions we want to use; We can also customize the starter ourselves in the future
Main startup class
Some notes
@SpringBoot application (function: mark a class to indicate that this class is the main configuration class of SpringBoot, and SpringBoot should run the main method of this class to start the SpringBoot application)
Enter this annotation: you can see that there are many other annotations above!
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { // ...... }
@Componentscan (function: automatically scan and load qualified components or beans, and load the bean definition into the IOC container)
This annotation is important in Spring and corresponds to the elements in the XML configuration.
@SpringBoot configuration (function: the configuration class of SpringBoot is marked on a class to indicate that it is a SpringBoot configuration class)
// Click in to get the following @ Component @Configuration public @interface SpringBootConfiguration {} @Component public @interface Configuration {}
The @ Configuration here indicates that this is a Configuration class, which is the xml Configuration file corresponding to Spring;
The @ Component inside shows that the startup class itself is just a Component in Spring and is responsible for starting the application!
Let's go back to the spring boot application annotation and continue.
@Enable autoconfiguration
Previously, we needed to configure things ourselves, but now SpringBoot can automatically configure them for us@ EnableAutoConfiguration tells SpringBoot to enable the auto configuration function so that the auto configuration can take effect;
@AutoConfigurationPackage: autoconfiguration package
@Import({Registrar.class}) public @interface AutoConfigurationPackage { }
@Import: the Spring underlying annotation @ import imports a component into the container
Function of Registrar.class: scan the package of the main startup class and all components in all sub packages under the package to the Spring container;
This analysis is finished. Step back and continue to look
@Import({AutoConfigurationImportSelector.class}): import components to the container
AutoConfigurationImportSelector: if the import selector is automatically configured, which component selectors will it import? Let's click this class to see the source code:
1. There is one such method in this class
// Obtain candidate configurations protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //The getSpringFactoriesLoaderFactoryClass () method here //The returned annotation class is the annotation class that we first saw to start the automatic import configuration file; EnableAutoConfiguration 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; }
2. This method also calls the static method of the springfactoryesloader class! We enter the loadFactoryNames() method of the springfactoryesloader class
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); //Here it calls the loadSpringFactories method again return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); }
3. Let's continue to click to view the loadSpringFactories method
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { //After obtaining the classLoader, we can see that what we get here is the class itself marked with EnableAutoConfiguration MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader); if (result != null) { return result; } else { try { //Go to get a resource "META-INF/spring.factories" Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap(); //Traverse the read resources and encapsulate them into a property 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 factoryClassName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String factoryName = var9[var11]; result.add(factoryClassName, factoryName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException var13) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13); } } }
4. Find a file that appears many times: spring.factories. Search it globally
spring.factories
We open spring.factories according to the source and see many automatic configuration files; This is the root of automatic configuration!
The real implementation of automatic Configuration is to search all META-INF/spring.factories Configuration files from the classpath, and instantiate the Configuration items under the corresponding org.springframework.boot.autoconfigure. Package into IOC container Configuration classes in the form of JavaConfig marked with @ Configuration through reflection, and then summarize them into an instance and load them into the IOC container.
Conclusion:
1. When springboot starts, obtain the value specified by EnableAutoConfiguration from META-INF/spring.factories under the classpath
2. Import these values into the container as an automatic configuration class, and the automatic configuration class will take effect to help us with automatic configuration;
3. The whole J2EE solution and automatic configuration are in the jar package of springboot autoconfigure;
4. It will import many automatic configuration classes (xxxAutoConfiguration) into the container, that is, import all components required for this scenario into the container and configure these components;
5. The automatic configuration class eliminates the need to manually write configuration injection function components;
SpringApplication
@SpringBootApplication public class SpringbootApplication { public static void main(String[] args) { SpringApplication.run(SpringbootApplication.class, args); } }
SpringApplication.run analysis
One is the instantiation of spring application, and the other is the execution of run method
SpringApplication
This class mainly does the following four things:
1. Infer whether the type of application is a normal project or a Web project
2. Find and load all available initializers and set them in the initializers property
3. Find and load all available initializers and set them in the initializers property
4. Infer and set the definition class of the main method, and find the main class to run
View constructor:
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) { // ...... this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.setInitializers(this.getSpringFactoriesInstances(); this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); }