Fourth, the analysis of the underlying mechanism of Spring Boot (Tomcat startup analysis + Spring container initialization + Tomcat how to associate Spring container) and the individual to write a startup Tomcat
@
- Fourth, the analysis of the underlying mechanism of Spring Boot (Tomcat startup analysis + Spring container initialization + Tomcat how to associate Spring container) and the individual to write a startup Tomcat
-
1. source code analysis Spring Boot is how to start Tomcat, and support access to @Controller Debug process analysis
- 1.1 Source code analysis: ( ) method
-
2. write their own implementation of Spring Boot underlying mechanism [Tomcat startup analysis + Spring container initialization + Tomcat how to associate Spring container].
- 2.1 Realize Task 1: Create Tomcat and start it.
- 2.2 Realize task phase 2: create Spring container
- 2.3 Implement Task Phase 3: Associate Tomcat with the Spring container and start the Spring container
- 3. Finally:
1. Source code analysis Spring Boot is how to start Tomcat, and support access to @Controller Debug process analysis
To analyze the source code, naturally, Debug is indispensable. Let's hit thebreakpoint Debug up.
1.1 Source code analysis: ( ) method
()
DeBug (, args); see how Spring Boot starts Tomcat
Our Debug goal: to hold on to a thread of code that sees tomcat being started: e.g.
()
// Here we go. Debug SpringApplication。run()
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
();
DefaultBootstrapContext bootstrapContext = ();
ConfigurableApplicationContext context = null;
();
SpringApplicationRunListeners listeners = (args);
(bootstrapContext, );
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = (listeners, bootstrapContext, applicationArguments);
(environment);
Banner printedBanner = (environment);
context = (); // Special analysis: Creating Containers
();
(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
(context); // Special analysis:Refreshing the application context,for example:Initialize Default Settings/Injecting relevantBean/activate (a plan) tomcat
(context, applicationArguments);
();
if () {
(new StartupInfoLogger()).logStarted((), stopWatch);
}
(context);
(context, applicationArguments);
} catch (Throwable var10) {
(context, var10, listeners);
throw new IllegalStateException(var10);
}
try {
(context);
return context;
} catch (Throwable var9) {
(context, var9, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
- : There are many types of containers, and the corresponding container will be created based on your
The default is a servlet, which is the web container/processing servlet.
protected ConfigurableApplicationContext createApplicationContext() {
return ();
}
The default is to go to this branch case SERVLET: return new AnnotationConfigServletWebServerApplicationContext();
public interface ApplicationContextFactory {
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
switch(webApplicationType) {
case SERVLET: // The default is to go into this branch
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
} catch (Exception var2) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
}
};
ConfigurableApplicationContext create(WebApplicationType webApplicationType);
static ApplicationContextFactory ofContextClass(Class<? extends ConfigurableApplicationContext> contextClass) {
return of(() -> {
return (ConfigurableApplicationContext)(contextClass);
});
}
static ApplicationContextFactory of(Supplier<ConfigurableApplicationContext> supplier) {
return (webApplicationType) -> {
return (ConfigurableApplicationContext)();
};
}
}
private void refreshContext(ConfigurableApplicationContext context) {
if () {
(context);
}
(context); // Special analysis,Real implementation of relevant mandates
}
protected void refresh(ConfigurableApplicationContext applicationContext) {
();
}
- Servlet in the
public final void refresh() throws BeansException, IllegalStateException {
try {
(); // Analyze this method in particular
} catch (RuntimeException var3) {
WebServer webServer = ;
if (webServer != null) {
();
}
throw var3;
}
}
- ApplicationContextFactory .java
public void refresh() throws BeansException, IllegalStateException {
synchronized() {
StartupStep contextRefresh = ("");
();
ConfigurableListableBeanFactory beanFactory = ();
(beanFactory);
try {
(beanFactory);
StartupStep beanPostProcess = ("-process");
(beanFactory);
(beanFactory);
();
();
();
(); // Special analysis,When the parent class has finished generalizing,Re-dynamically bind the mechanism back to the
();
(beanFactory);
();
} catch (BeansException var10) {
if (()) {
("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
();
(var10);
throw var10;
} finally {
();
();
}
}
}
protected void onRefresh() {
();
try {
(); establish webServer 可以理解成会establish指定 webserver (computer)-tomcat
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}
private void createWebServer() {
WebServer webServer = ;
ServletContext servletContext = ();
if (webServer == null && servletContext == null) {
StartupStep createWebServer = ().start("");
ServletWebServerFactory factory = ();
("factory", ().toString());
= (new ServletContextInitializer[]{
()}); // Special analysis,utilization TomcatServletWebServerFactory Create aTomcatWEbServer
();
().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle());
().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, ));
} else if (servletContext != null) {
try {
().onStartup(servletContext);
} catch (ServletException var5) {
throw new ApplicationContextException("Cannot initialize servlet context", var5);
}
}
();
}
Tomcat will be created and started.
public WebServer getWebServer(ServletContextInitializer... initializers) {
if () {
();
}
Tomcat tomcat = new Tomcat();
File baseDir = != null ? : ("tomcat");
(());
Connector connector = new Connector();
(true);
().addConnector(connector);
(connector);
(connector);
().setAutoDeploy(false);
(());
Iterator var5 = ();
while(()) {
Connector additionalConnector = (Connector)();
().addConnector(additionalConnector);
}
((), initializers);
return (tomcat);
}
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, () >= 0, ());
}
public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
= new Object();
= new HashMap();
(tomcat, "Tomcat Server must not be null");
= tomcat;
= autoStart;
= shutdown == ? new GracefulShutdown(tomcat) : null;
(); // Analyze this method
}
- (); Initializes the Tomcat server.
private void initialize() throws WebServerException {
("Tomcat initialized with port(s): " + (false));
synchronized() {
try {
();
Context context = ();
((event) -> {
if ((()) && "start".equals(())) {
();
}
});
(); // ********* activate (a plan) Tomcat
();
try {
(context, (), ().getClassLoader());
} catch (NamingException var5) {
}
();
} catch (Exception var6) {
();
();
throw new WebServerException("Unable to start embedded Tomcat", var6);
}
}
}
2. write their own implementation of Spring Boot underlying mechanism [Tomcat startup analysis + Spring container initialization + Tomcat how to associate Spring container].
**Spring Boot injection to hit the ioc container: the underlying mechanism: is still: we implement the Spring container that set of mechanisms
IO/File Scanning + Annotation + Reflection + Collections + Mapping
** 。
Rely on Maven to configure the appropriate requiredjar
Package.
<?xml version="1.0" encoding="UTF-8"? >;xml version="1.0" encoding="UTF-8"?
<project xmlns="/POM/4.0.0"
xmlns:xsi="http:///2001/XMLSchema-instance"
xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0." >
<modelVersion>4.0.0</modelVersion>
<groupId></groupId>
<artifactId>mySpringBoot</artifactId>
<version>1.0-SNAPSHOT</version>
<! -- Importing SpringBoot parent project - prescribed writeups - >
<parent>
<groupId> </groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
</parent>
<! -- Import web project scenario launcher: will automatically import all dependencies [libraries/jars] of jar packages related to web development -- <!
<! -- Later on, we will explain what dependencies spring-boot-starter-web introduces -- > <!
<dependencies>
<dependency>
<groupId> </groupId>
<artifactId>spring-boot-starter-web</artifactId>
<! --
Since we have to create the Tomcat object and start it ourselves.
So let's exclude the embedded spring-boot-starter-tomcat first.
-->
<exclusions>;
<exclusions>
<groupId> </groupId>.
<artifactId>spring-boot-starter-web</artifactId>.
</exclusion>
</exclusions>
</dependency>.
<! -- We specify the tomcat version and introduce tomcat dependencies/libraries -- >!
<! --
1. Use the specified tomcat 8.5.75, and ask your friends to bring in this version as well.
2. If we introduce our own specified tomcat, we must remember to exclude spring-boot-stater-tomcat from the front.
3. If you do not exclude, there will be GenericServlet Not Found error.
-->
<dependency>.
<groupId> </groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.75</version>
</dependency>
</dependency> <dependency>
<groupId> </groupId> </groupId>
<artifactId>tomcat-jasper</artifactId> <groupId></groupId>
<version>8.5.75</version>
</dependency>
</dependencies>
</project>.
2.1 Realize Task 1: Create Tomcat and start it.
package ;
import ;
public class MySpringApplication {
// Here we create a tomcat object and associate it with the Spring container and start it up
public static void run() {
try {
// Create the tomcat object
Tomcat tomcat = new Tomcat(); // Create a tomcat object.
// 1. Make it possible for tomcat to forward requests to the spring web container.
// 2. "/myspboot" is the application context of our project, which is what we specified when we configured tomcat.
("/app", "E:\\\Java\\\SpringBoot\\quickstart\\mySpringBoot");
//
// Set the monitor port to 9090
(8080).
// Start Tomcat
(); // Start Tomcat.
// Wait for the request to come in
("===9090=== Waiting for request ========="); ("===9090=== Waiting for request ========="); ().await(); // Wait for request access.
().await();
} catch (Exception e) {
(); } catch (Exception e) {
} finally {
}
}
}
2.2 Realize task phase 2: create Spring container
bean object.
package ;
import ;
@Controller // Add to ioc container to manage
public class Monster {
}
The config configuration class for the bean object
package ;
import ;
import ;
import ;
import ;
/*
Here is a question, how does the container know which packages to scan?
The packages to be scanned can be specified in the configuration class: @ComponentScan("")
MyConfig Configuration Class - as a configuration file for Spring
*/
@ComponentScan("")
@Configuration // Labeling: setup class
public class MyConfig {
// Inject the bean - monster object into the Spring container.
@Bean
public Monster monster() {
return new Monster();
}
}
controller The controller that handles the business request
package ;
import ;
import ;
@RestController // @Controller + @ResponseBod
public class MyHiController {
@RequestMapping("/myhi") // Setting the request mapping path
public String hi() {
return "hi my MyHiController ";
}
}
2.3 Implement Task Phase 3: Associate Tomcat with the Spring container and start the Spring container
package ;
import ;
import ;
import ;
import ;
import ;import ;import ;import ;import
import ;
import ;import ;import ;import ;import
import ;import ;import ;import ;import
import ;
/**
* Interpretation.
* 1. create our Spring container
* 2. Load/associate the Spring container's configuration - in an annotated way
* 3. complete the Spring container configuration of the creation of beans, dependency injection
* 4. Create the front-end controller DispatcherServlet and let it hold the Spring container.
* 5. When the DispatcherServlet holds the container, you can distribute the mapping, please recall our implementation of SpringMVC partners
* 6. here onStartup is called by Tomcat, and passes the ServletContext object into the
*/
public class MyWebApplicationInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext)
public void onStartup(ServletContext servletContext) throws ServletException {
("startup...") ;)
// load Spring web application configuration => container
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext(); ; // load Spring web application configuration => container.
().
(); // Finish creating and configuring the bean.
// 1. Create the front-end controller that is important to register when the DispatcherServlet is created.
// 2. Let the DispatcherServlet hold the container.
// 3. This allows for mapping and distribution, recalling the SpringMVC mechanism (implemented by myself)
DispatcherServlet dispatcherServlet = new DispatcherServlet(ac);
// Return the object
registration = ("app", dispatcherServlet); // return the object.
// When tomcat starts, load the dispatcherServlet
(1); // When tomcat starts, load the dispatcherServlet.
// Intercept the request and distribute it
// Here the instructor is hinting at "/" and "/*", which were used in the instructor's lecture on the java web.
("/").
}
}
package ;
public class MyMainApp {
public static void main(String[] args) {
// activate (a plan)MySpringBoot sports event/programs
();
}
}
3. Finally:
"In this final chapter, I would like to express my gratitude to each and every one of my readers. Your attention and responses have been a source of motivation for me to create, and I have drawn endless inspiration and courage from you. I will keep your encouragement in my heart and continue to struggle in other areas. Thanks to you all, we will always meet again at some point."