Hello everyone, I am early morning, before writing a lot of articles about SpringBoot, I believe that you have felt SpringBoot relative to the traditional Spring to bring convenient, so this article we will analyze the convenience of SpringBoot in the end convenient where

I don’t know if you’ve noticed, but when we create a SpringBoot project, we use the following startup class

@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code

From a code point of view, it is obvious that the @SpringBootApplication annotation and the SpringApplication class and its Run method are at the core.

So in this article we’ll take a look at @SpringBootApplication

@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 {
    ...
}Copy the code

The three important annotations are @SpringBootConfiguration, @EnableAutoConfiguration and @ComponentScan. Let’s take a look at each of them.

A: @ SpringBootConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}Copy the code

It turns out he’s using @Configuration.

The @Configuration annotation is used to define a JavaConfig Configuration class that replaces an XML Configuration file. The annotated class contains one or more @bean annotated methods. These methods will be AnnotationConfigApplicationContext or AnnotationConfigWebApplicationContext scanned, and used to construct the bean definition, initialize the Spring container. This is the configuration recommended by the SpringBoot community.

Differences between @Configuration and traditional XML Configuration files:
  1. File structure

    Traditional XML:


    <? xml version="1.0" encoding="UTF-8"? > <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
        xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd" default-lazy-init="false">
    
    
    </beans>Copy the code

    Using the @ the Configuration:


    @Configuration
    public class TestConfig {
    }Copy the code

  2. The definition of a bean

    Traditional XML:


    <bean id="testService" class="TestServiceImpl">
    </bean>Copy the code

    Using the @ the Configuration:


    @Configuration
    public class TestConfig {
        @Bean
        public TestService testService() {returnnew TestServiceImpl(); }}Copy the code

So any Java class that uses @Configuration indicates that it is a Configuration class.
The return value of any method labeled @bean is registered with Spring’s IoC container as a Bean definition, and the method name defaults to the id of the Bean definition.

2: @ ComponentScan

This annotation is important in Spring, and if you understand @ComponentScan, you understand Spring.
You all know that Spring is a dependency injection framework, and everything is around bean definitions and their dependencies.
But Spring doesn’t know which beans you define unless you tell spring where to find them.
What @ComponentScan does is tell Spring where to find the defined bean


The basePackages attribute controls the scope of automatic scanning for @ComponentScan. If no scope is specified for @ComponentScan, the default scope is to scan from the package of the class in which @ComponentScan is declared.

So we can see that the directory structure of the created SpringBoot project generally looks like this



The startup class is always in the root directory of the project so that all defined beans can be scanned without configuring the scan scope

3: @ EnableAutoConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class[] exclude() default {};

    String[] excludeName() default {};
}Copy the code

The two important annotations here are @autoConfigurationPackage and @import

@AutoConfigurationPackage

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({Registrar.class}) public  @interface AutoConfigurationPackage { }Copy the code

It turns out that he has brought in the Registrar class using the @import annotation

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    Registrar() {
    }

    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
    }

    public Set determineImports(AnnotationMetadata metadata) {
        returnCollections.singleton(new AutoConfigurationPackages.PackageImport(metadata)); }}Copy the code

So what is this class for? Let’s follow through and see what the registerBeanDefinitions method does.



Here to find
new PackageImport(metadata).getPackageName()Returns the package components of the siblings and children of the current main program class.

This also proves that @ComponentScan scans the package of its class by default.

@Import({AutoConfigurationImportSelector.class})

Next we see AutoConfigurationImportSelector this class

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if(! this.isEnabled(annotationMetadata)) {return NO_IMPORTS;
    } else {
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
        AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
        returnStringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }}Copy the code

This method calls the getAutoConfigurationEntry method

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
    if(! this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;
    } else {
        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
        List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        configurations = this.removeDuplicates(configurations);
        Set exclusions = this.getExclusions(annotationMetadata, attributes);
        this.checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = this.filter(configurations, autoConfigurationMetadata);
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        returnnew AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); }}Copy the code

Here we focus on see getCandidateConfigurations method, first breakpoint see methods return values



This method returns a list of classes that need to be instantiated, and with it Spring can load the classes that need to be instantiated into the JVM through the classloader.
Now we look at the code for this method and see that it borrows methods from the SpringFactoriesLoader class

protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List 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;
}Copy the code

Look again at the loadFactoryNames method

public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap result = (MultiValueMap)cache.get(classLoader);
    if(result ! = null) {return result;
    } else{ try { Enumeration urls = classLoader ! = null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap(); / /... Omit the cache. The put (this, result);return result;
        } catch (IOException var13) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13); }}}Copy the code

It turns out that he’s reading a file called Spring.factories



For example, let’s look at the redis configuration



Click to have a look

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    ......
}Copy the code

ConditionalOnClass({redisoperations.class}) ConditionalOnClass({redisoperations.class}) specifies that the RedisOperations class must exist, otherwise the configured class will not be resolved.


Take a look at the RedisProperties class

public class RedisProperties {
    private int database = 0;
    private String url;
    private String host = "localhost"; private String password; private int port = 6379; private boolean ssl; private Duration timeout; private RedisProperties.Sentinel sentinel; private RedisProperties.Cluster cluster; private final RedisProperties.Jedis jedis = new RedisProperties.Jedis(); private final RedisProperties.Lettuce lettuce = new RedisProperties.Lettuce(); . Omit}Copy the code

Doesn’t that look familiar! This is the information we need to configure when using Redis in the application.properties
The configuration is as follows:

Spring. Redis. Host = 127.0.0.1 spring. Redis. Port = 6379 spring. Redis. Timeout = 0 spring. Redis. Password =Copy the code

You can also see that Redis has the host and port attributes configured for us by default. Therefore, when configuring Redis, if the port number is the default 6379, we can not write the reason.


So the idea behind @enableAutoConfiguration is to search all meta-INF/Spring.Factories configuration files from your classpath, And will it org. Springframework. Boot. Autoconfigure. EnableutoConfiguration corresponding Configuration items by reflecting instance into the corresponding annotation @ Configuration JavaConfig forms of IoC container Configuration Class, then summarized into one and loaded into the IoC container.


Four: the ending

@springBootApplication We’re done. In the next article we’ll look at the SpringApplication class


For springBoot do not know friends can see my springBoot series tutorial