Spring boot -- loading in the preparation stage of spring application

Keywords: Programming Spring xml Java Tomcat

Learning notes are notes made according to my own needs and understanding after learning the core technology of Spring Boot 2.0 in-depth practice by brother Ma on mooc.com.

Preface

Spring boot is built based on spring, that is to say, Spring Framework is the basis of learning spring boot well.

First of all, the premise of understanding the spring application boot class in spring boot is to simply understand the basic technology of Spring Framework.

The basic technology of Spring Framework includes the following points, which are listed for my review and summary later

  • Spring schema annotation A kind of
  • Spring BeanFactory
  • Spring application context A kind of
  • Loading and life cycle of Spring Bean
  • Spring factory loading mechanism A kind of
  • Spring application context function extension A kind of
  • IOC (inversion of control) & di (dependency injection) AOP (aspect oriented programming)
  • spring mvc
  • Spring application event / listener A kind of
  • Spring Environment abstraction A kind of

The checkmark is for the guidance class SpringApplication.

Spring boot derivative technology

  • SpringApplication
  • SpringApplication Builder API
  • Spring application running listener
  • SpringApplication parameters
  • Spring application failure analysis
  • SpringApplication application event / listener

The preparation stage of spring application can also be called the constructor stage. Let's take a look at the source code.

/**
 * Create a new {@link SpringApplication} instance. The application context will load
 * beans from the specified primary sources (see {@link SpringApplication class-level}
 * documentation for details. The instance can be customized before calling
 * {@link #run(String...)}.
 * @param resourceLoader the resource loader to use
 * @param primarySources the primary bean sources
 * @see #run(Class, String[])
 * @see #setSources(Set)
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   //The first part
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

    
   //The second part
   this.webApplicationType = deduceWebApplicationType();
    
    
    //The third part
   setInitializers((Collection) getSpringFactoriesInstances(
         ApplicationContextInitializer.class));
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    
    
    //The fourth part
   this.mainApplicationClass = deduceMainApplicationClass();
}

There are four parts in the preparation stage

  • The first part: configure our source. We can also learn from the source annotation that this source is the main source that can load all bean s from the application context. Generally speaking, we annotate the @ SpringBootApplication schema. For pattern annotation, please refer to my previous articles.
  • The second part: infer the type of Web application.
  • Part three: application context initializer and application event listener, which can be viewed Spring boot -- loading in the preparation stage of spring application (2)
  • The fourth part: derive and reference the main class.

Configuration: Spring Bean source

JAVA configuration Class

The class marked by Spring schema annotation is used for Java configuration class in Spring annotation driver.

For example, the default startup class of our project is springbootdivelearnappplication in my project

@SpringBootApplication
public class SpringBootDiveLearnApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringBootDiveLearnApplication.class, args);
   }
}

As we can see, this boot class configures a spring pattern annotation @ SpringBootApplication

Let's take a look at the pattern annotation

@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 {}

There are two special annotations @ SpringBootConfiguration @EnableAutoConfiguration on this annotation. If we look up @ SpringBootConfiguration further, we can find that this annotation is actually the "derived" annotation of @ Component. And @ EnableAutoConfiguration is an assembly annotation of interface programming.

Therefore, in the guidance class springbootdivelearnappplication, we will put springbootdivelearnappplication as the startup parameter in the SpringApplication.run method of the main function method.

XML context profile

Used for XML files in spring traditional configuration drivers.

We know how to start the container when the class configured by JAVA is used as the parameter of the boot class, that is, SpringApplication.run(SpringBootDiveLearnApplication.class, args);

So how does XML start

SpringApplication springApplication = new SpringApplication();
springApplication.setSources();
springApplication.run(args);

We can add parameters to the. setSources method to configure the source.

Let's take a look at the. setSources method to understand this configuration method.

/**
 * Set additional sources that will be used to create an ApplicationContext. A source
 * can be: a class name, package name, or an XML resource location.
 * <p>
 * Sources set here will be used in addition to any primary sources set in the
 * constructor.
 * @param sources the application sources to set
 * @see #SpringApplication(Class...)
 * @see #getAllSources()
 */
public void setSources(Set<String> sources) {
   Assert.notNull(sources, "Sources must not be null");
   this.sources = new LinkedHashSet<>(sources);
}

We can see the English explanation in the annotation. The parameters can be class name, package name and XML source path.

So what method does spring boot use to load the two data sources separately.

The answer is the construction method in org.springframework.boot.BeanDefinitionLoader

/**
 * Create a new {@link BeanDefinitionLoader} that will load beans into the specified
 * {@link BeanDefinitionRegistry}.
 * @param registry the bean definition registry that will contain the loaded beans
 * @param sources the bean sources
 */
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
   Assert.notNull(registry, "Registry must not be null");
   Assert.notEmpty(sources, "Sources must not be empty");
   this.sources = sources;
   //JAVA configuration CLASS 
   this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
   //XML configuration 
   this.xmlReader = new XmlBeanDefinitionReader(registry);
   if (isGroovyPresent()) {
      this.groovyReader = new GroovyBeanDefinitionReader(registry);
   }
   this.scanner = new ClassPathBeanDefinitionScanner(registry);
   this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}

Read through AnnotatedBeanDefinitionReader and XmlBeanDefinitionReader respectively and load the configuration source resolution as Spring Bean.

Where does BeanDefinitionLoader reference.

It is in the guidance class SpringApplication

/**
 * Factory method used to create the {@link BeanDefinitionLoader}.
 * @param registry the bean definition registry
 * @param sources the sources to load
 * @return the {@link BeanDefinitionLoader} that will be used to load beans
 */
protected BeanDefinitionLoader createBeanDefinitionLoader(
      BeanDefinitionRegistry registry, Object[] sources) {
   return new BeanDefinitionLoader(registry, sources);
}

For the reference in this method, if we look up step by step, the final method is SpringApplication.run().

We can also confirm our conclusion that there are two data sources in the configuration phase of spring boot.

Inference: Web application type and main boot class

We know that spring boot can be used not only as a WEB project, but also as a non WEB project, so how can we judge whether the current engineer WEB or non WEB. We can see it from the workbench. As shown in the figure, the following is the startup log printed by non WEB type workbench.

 
Figure 5.PNG

We can see that the output log does not show that Tomcat is used to start and there is no port 8080.

The following output will be displayed in the startup log of the WEB project.

 
Figure 6.PNG

From the output log in the figure, it can be seen that both Tomcat Server and 8080 port are available.

How spring boot infers application types

Infer the type of Web application according to whether there are relevant implementation classes in the current application ClassPath, including:

  • Web Reactive: the classpath corresponding to WebApplicationType.REACTIVE

    org.springframework. web.reactive.DispatcherHandler

  • Web Servlet: the class path corresponding to WebApplicationType.SERVLET org.springframework.web.servlet.DispatcherServlet“

  • Non Web: WebApplicationType.NONE

The judgment method is org.springframework.boot.springapplication ා deducewebapplicationtype

/**
* Springboot How to judge the current WEB application type at startup
*/
private WebApplicationType deduceWebApplicationType() {
    /**
    * When there is a Web Reactive class path under the class path, and
    *WebApplicationType.SERVLET class path does not exist to enable
    * WEB REACTIVE The container is called Netty.
    */
   if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
         && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
         && !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
      return WebApplicationType.REACTIVE;
   }
   /**
   * When none of the Classpaths exist, non WEB types are enabled
   */
   for (String className : WEB_ENVIRONMENT_CLASSES) {
      if (!ClassUtils.isPresent(className, null)) {
         return WebApplicationType.NONE;
      }
   }
    /**
    *  If none is satisfied, TOMCAT is enabled by default 
    */
   return WebApplicationType.SERVLET;
}

The above method is to determine the startup application type.

How spring boot infers the main boot class

We will wonder, isn't spring boot the main class by default? Similar to the following code

@SpringBootApplication
public class SpringBootDiveLearnApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringBootDiveLearnApplication.class, args);
   }
}

We can clearly see that the Main Class is springbootdivelearnappplication, but don't forget that spring boot has a variety of startup methods, and the first parameter in SpringApplication.run(); is variable, in other words, I take other classes and add @ SpringBootApplication annotation, and put it in SpringApplication.run(); Method, then that class should be the Main Class, not the current class. So how does spring boot judge the Main Class.

Reference method: org.springframework.boot.springapplication ා deducemainapplicationclass

/**
* Use exception stack to judge current main class
*/
private Class<?> deduceMainApplicationClass() {
   try {
       
      StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
      for (StackTraceElement stackTraceElement : stackTrace) {
         if ("main".equals(stackTraceElement.getMethodName())) {
            return Class.forName(stackTraceElement.getClassName());
         }
      }
   }
   catch (ClassNotFoundException ex) {
      // Swallow and continue
   }
   return null;
}

spring uses the exception stack to traverse and finally determine the main method. Let's Debugger.

 
Figure 7.PNG

We can see that there is only the last stack information, that is, the method name in the class named springbootdivelearnappplication is main, so we can deduce that springbootdivelearnappplication is the main class.

Spring boot's main startup class is derived by spring itself, so we should not assume that the main class is passed to the spring container.

At the end of the article, we recommend a blog post, which was discovered recently. It's found that it's well written. According to the content of the blog post, we can go to debugger to better understand the spring Framework.

Article link: Give you a list of Spring Boot knowledge



By Neal lemon
Link: https://www.jianshu.com/p/f3d40e4b3d21
Source: Jianshu
The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source.

Posted by NiallThistle on Sun, 22 Mar 2020 09:18:17 -0700