Coordinate Hangzhou, usually playing games, reading books, writing bugs for the company, but fortunately for the company to recruit new blood, in the screening resume, found that everyone must fill in a SpringBoot, including (master SpringBoot, familiar with SpringBoot, familiar with the use of, proficient and so on) what and proficient? Looks like the boy’s gonna have to face the music.

So, as an honest and composed interviewer,SpringBoot will need to have a deep discussion with the job candidate. Basically, the discussion includes the principle of automatic assembly, what is the embedded server container, what are the methods to generate beans, etc. Today’s topic is to discuss how to start the embedded servlet Dynamic and configured

Why can I start a Web project using Java-JAR

Reference to SpringBoot programming thought 2.2 Running SpringBoot application

Our project launcher Class is loaded and executed by JarLauncher, and the start-class property in the META−INF/ manifest.mf resource (that is, our launch Class) is managed by JarLauncher for the project launcher Class

If you want to try it out privately, you can add the following plugin to your Maven file and package and unzip the file to view the manifest.mf file in your project

 1<plugin>

2   <groupId>org.apache.maven.plugins</groupId>

3   <artifactId>maven-jar-plugin</artifactId>

4   <version>3.0.2</version>

5   <configuration>

6      <archive>

7         <manifest>

8            <addClasspath>true</addClasspath>

9            <classpathPrefix>lib/</classpathPrefix>

10            <mainClass>com.wang.springboottest.SpringBootTestApplication</mainClass>

11         </manifest>

12      </archive>

13   </configuration>

14</plugin>

Copy the code

How come there is no web.xml file in the project

Remember that our Servlet versions prior to 3.0 included web.xml How does springBoot start the servlet and how does springBoot configure the filters and listeners

After the above three new features, we can discard the web. XML file, specific in SpringBoot how to use, here to sell the mystery, the source code will see later

How to change the bound port number

The SpringBoot project is created with a configuration file that allows you to configure various properties, including binding port numbers. And why write content in configuration file, data will be synchronized to the embedded Server

  • Environment variable (-. = but I failed to use server.port environment variable)

How do embedded servlets start

What is an embedded servlet

Package the project into a WAR package. 2. Copy the WAR package to webapps in the Tomcat directory. 3 But SpringBoot does not require us to download Tomcat ourselves. Spring has already imported the necessary third-party JAR packages into our project, as shown below

1  <dependency>

2            <groupId>org.springframework.boot</groupId>

3            <artifactId>spring-boot-starter-web</artifactId>

4        </dependency>

Copy the code

contains

1        <dependency>

2      <groupId>org.springframework.boot</groupId>

3      <artifactId>spring-boot-starter-tomcat</artifactId>

4      <version>2.2.5.RELEASE</version>

5      <scope>compile</scope>

6    </dependency>

Copy the code

This JAR package contains the various Tomcat core JARS

In the startup diagram, we can clearly see the Tomcat print log

Of course, springBoot does not only support Tomcat embedding, we can replace poM files with embedded servlets as we can see from the official documentation

1Spring Boot includes support for embedded Tomcat, Jetty, And Undertow servers. Most developers use the appropriate "Starter" to obtain a fully configured instance. the embedded server listens for HTTP requests on port 8080.

Copy the code

Of course the substitution is simple as follows

 1  <dependency>

2            <groupId>org.springframework.boot</groupId>

3            <artifactId>spring-boot-starter-web</artifactId>

4            <exclusions>

5                <exclusion>

6                    <groupId>org.springframework.boot</groupId>

7                    <artifactId>spring-boot-starter-tomcat</artifactId>

8                </exclusion>

9            </exclusions>

10        </dependency>

11

12        <dependency>

13            <groupId>org.springframework.boot</groupId>

14            <artifactId>spring-boot-starter-jetty</artifactId>

15        </dependency>

Copy the code

This means that after Spring starts the main file, it directly launches the embedded Jetty to serve the servlet container

As usual, directly above:

JettyWebServer is clearly visible

The following is a detailed and boring source code explanation, exactly how springBoot starts the embedded container (below is to take the embedded Tomcat server)

  • First we look at the Run method of the SpringApplication that launches the class, which creates the application context first
 1  context = createApplicationContext();

2

3Class<? > contextClass =this.applicationContextClass;

4        if (contextClass == null) {

5            try {

6                switch (this.webApplicationType) {

7                / / we project contains webjar package, belongs to the servlet projects, and produce AnnotationConfigServletWebServerApplicationContext object

8                case SERVLET:

9                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);

10                    break;

11                case REACTIVE:

12                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);

13                    break;

14                default:

15                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);

16                }

17            }

18            catch (ClassNotFoundException ex) {

19                throw new IllegalStateException(

20                        "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);

21            }

22        }

23        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);

Copy the code
  • Next AnnotationConfigServletWebServerApplicationContext is our task, he will be created in a context server, as follows
 1  @Override

2    protected void onRefresh(a) {

3        super.onRefresh();

4        try {

5          // Create a Tomcat server to initialize the servlet

6            createWebServer();

7        }

8        catch (Throwable ex) {

9            throw new ApplicationContextException("Unable to start web server", ex);

10        }

11    }

Copy the code
  • Enter the createWebServer
 1  private void createWebServer(a) {

2    // The Server has not been initialized yet, so the following two items are empty

3        WebServer webServer = this.webServer;

4        ServletContext servletContext = getServletContext();

5        if (webServer == null && servletContext == null) {

6      // Not the point, just a little introduction

7      // get the web service factory for the current project, such as the web's default TomcatWeb service or alternative jetty, undertow

8      // And register as a Spring bean

9            ServletWebServerFactory factory = getWebServerFactory();

10      // Further analysis, this is our focus, and also the focus of embedded Tomcat

11            this.webServer = factory.getWebServer(getSelfInitializer());

12        }

13        else if(servletContext ! =null) {

14            try {

15                getSelfInitializer().onStartup(servletContext);

16            }

17            catch (ServletException ex) {

18                throw new ApplicationContextException("Cannot initialize servlet context", ex);

19            }

20        }

21        initPropertySources();

22    }

Copy the code
  • Dive further into getWebServer
 1    @Override

2    public WebServer getWebServer(ServletContextInitializer... initializers) {

3        if (this.disableMBeanRegistry) {

4            Registry.disableRegistry();

5        }

6        Tomcat tomcat = new Tomcat();

7        File baseDir = (this.baseDirectory ! =null)?this.baseDirectory : createTempDir("tomcat");

8        tomcat.setBaseDir(baseDir.getAbsolutePath());

9        Connector connector = new Connector(this.protocol);

10        connector.setThrowOnFailure(true);

11        tomcat.getService().addConnector(connector);

12        customizeConnector(connector);

13        tomcat.setConnector(connector);

14        tomcat.getHost().setAutoDeploy(false);

15        configureEngine(tomcat.getEngine());

16        for (Connector additionalConnector : this.additionalTomcatConnectors) {

17            tomcat.getService().addConnector(additionalConnector);

18        }

19        prepareContext(tomcat.getHost(), initializers);

20        return getTomcatWebServer(tomcat);

21    }

Copy the code

This is not relevant to this article, and the following chapter will publish a version of << In-depth understanding of Tomcat in SpringBoot >>

Initializing the Tomcat object −> Initializing the Connector −> Initializing the Service component −> Initializing the Host component −> Initializing the Engine component −> Initializing the Context component −> Initializing the Servlet container

I believe everyone is familiar with this picture, and I will paste it here again. After all, Tomcat is just like our girlfriend, who not only uses it every day, but never gets tired of seeing it

Tomcat architecture diagram
  • Maybe people who are not familiar with Tomcat can’t accept this kind of jump (in fact, I can’t watch it myself, but as the first time to write a blog, I hope you can understand it a little bit). Here I will draw a sequence diagram and paste the stack information for you to have a rough understanding
  • The stack information is as follows:
  • Better viewing effect with sequence diagram
  • Let’s go further and initialize the Servlet container
 1private void selfInitialize(ServletContext servletContext) throws ServletException {

2   // The spring context sets the servletContext

3   prepareWebApplicationContext(servletContext);

4   // Register the servlet wrapper class for the application context properties

5   registerApplicationScope(servletContext);

6   / / the registration servlet each attribute to the Spring container singleton bean (include the servletContext, servletConfig, contextAttributes...)

7   WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);

8  / / the key to cough up, getServletContextInitializerBeans will initialize ServletContextInitializerBeans object

9  // This object does a lot of bean initialization, which I'll cover later

10   for (ServletContextInitializer beans : getServletContextInitializerBeans()) {

11             // Call the start method to configure the specific servlet filter listener, etc

12      beans.onStartup(servletContext);

13   }

14}

Copy the code
  • – Initializes the Servlet context Bean object

     1@SafeVarargs

    2  public ServletContextInitializerBeans(ListableBeanFactory beanFactory,

    3          Class<? extends ServletContextInitializer>... initializerTypes)
     
    {

    4      // Initialize the array

    5      this.initializers = new LinkedMultiValueMap<>();

    6      // a

    7      this.initializerTypes = (initializerTypes.length ! =0)? Arrays.asList(initializerTypes)

    8              : Collections.singletonList(ServletContextInitializer.class);

    9      // b

    10      addServletContextInitializerBeans(beanFactory);

    11      // c

    12      addAdaptableBeans(beanFactory);

    13      List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()

    14              .flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))

    15              .collect(Collectors.toList());

    16      this.sortedList = Collections.unmodifiableList(sortedInitializers);

    17      logMappings(this.initializers);

    18  }

    Copy the code
  1. InitializerTypes a: due to the parameter passed is null, so will the new ServletContextInitializer, you remember about the disappearance of the web. The above XML? Yes, we did start ending echo, (brother, double-click on the 666, attention is not lost)

  2. B: Focus on initializing the dispatcherServlet into the spring context container

    1. 1private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {

      2        for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {

      3            for (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory,

      4                    initializerType)) {

      5                addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);

      6            }

      7        }

      8    }

      Copy the code
    2. At this time there will be a classmate ask, why is loaded dispatcherServlet here, ServletContextInitializer there are many subclasses of ah, I do not know whether we still remember the automatic configuration principle (here not to tell, if not many people know, the next issue of can explain) we are in s Pring – the boot – autoconfigure spring. Under the jars of factories see org. Springframework. Boot. Autoconfigure. Web. Servlet. DispatcherServletAut OConfiguration is an automatic configuration class, and our project already conforms to its condition(as follows), so at the initial stage of the project, the beans under this class include (DispatcherServlet, MultipartResolver) , DispatcherServletRegistrationBean) is the beanFactory scanning to load the class to the bean plant

    3. 1@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)

      2@Configuration(proxyBeanMethods = false)

      3@ConditionalOnWebApplication(type = Type.SERVLET)

      4@ConditionalOnClass(DispatcherServlet.class)

      5@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)

      6public class DispatcherServletAutoConfiguration

      7


      Copy the code
    4. At this point, our servlet is successfully initialized

  3. C: Key, register to upload file configuration, servlet registry, filter registry, listener registry to spring container

    1.  1protected void addAdaptableBeans(ListableBeanFactory beanFactory) {

      2    // A

      3        MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);

      4      // B

      5        addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig));

      6    // C

      7        addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());

      8        for(Class<? > listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {

      9      // D

      10            addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType,

      11                    new ServletListenerRegistrationBeanAdapter());

      12        }

      13    }

      Copy the code
    2. A: Upload file to configure bean registration

    3. B: Register servlets included with Spring. factories (except dispatcherServlet)

    4. C: Register the Filter contained in spring.factories into the spring container

    5. D: Register the listener contained in spring.factories into the Spring container

conclusion

SpringBoot’s embedded containers demonstrate flexible extensibility and use of auto-assembly and IOC containers that we can do for ourselves during the launch of a project.

Of course, there are a lot of omissions in the article, in fact, those who take a little time to look at the source can also guess the general meaning of the period is still dependent on our cliche of Spring ApplicationContext and BeanFactory

nagging

I have been working for more than three years. I haven’t recorded the profound problems and bugs in my work, but I often encounter them in my daily work, which makes me forget them quickly. Therefore, I hereby write this article to discuss and retrieve the difficult problems encountered in my work.

If the article has the wrong point, please move the little hand, help to show one or two, let us grow up together, become the bully in the interview together. Offers are too many to get, counting money hand cramps

Resources: https://www.cnkirito.moe/servlet-explore/ (for her lost web. XML)

Spring Boot programming thought of Little Marco