De la tortura del alma del entrevistador desde lo más profundo de la auditoría interna: “Cuéntame sobre el proceso de arranque de springboot”; el
entrevistador con cara de confusión: “Simplifica la configuración de spring, principalmente porque tiene la función de montaje automático, y puede comenzar directamente, porque tiene un contenedor tomcat incrustado";
entrevistador: "Bueno, sí, estos son algunos de sus conceptos, aún no ha respondido mi pregunta, cómo comenzó y qué pasó cuando fue comenzó?";
Entrevistador confundido: "Ah~~~ No sé... Soy muy hábil en usarlo, ¡pero no sé qué hace en él!"; Entrevistador: "
Comprender el principio interno es para ayudarnos a expandirnos y al mismo tiempo verificar la capacidad de aprendizaje de una persona, si desea llevar su carrera profesional al siguiente nivel, debe conocer estas cosas de bajo nivel, está bien, regrese y espere las noticias. Entrevistador
: ↓
¿Qué es Spring Boot?
Springboot depende de Spring. En comparación con Spring, además de tener todas las funciones de Spring, Springboot no necesita una configuración xml engorrosa, que depende de su propia función potente de ensamblaje automático; y tiene integrados Tomcat, Jetty y otros contenedores web, springmvc integrado permite que springboot se ejecute directamente sin contenedores adicionales y proporciona algunas características no funcionales comunes en proyectos a gran escala, como servidores integrados, seguridad, indicadores, detección de salud, configuración externa, etc.
De hecho, todo el mundo sabe que spring, boot significa arranque. Por lo tanto spring boot es en realidad una herramienta para iniciar un proyecto spring, en una palabra spring boot es un framework que sirve al framework, también se puede decir que spring boot es una herramienta que simplifica la configuración de spring;
Características principales de Spring Boot
1. Proyecto Spring que puede ejecutarse de forma independiente: Spring Boot puede ejecutarse de forma independiente en forma de un paquete jar.
2. Contenedor de servlet integrado: Spring Boot puede optar por integrar Tomcat, Jetty o Undertow, y no es necesario implementar proyectos en forma de paquetes de guerra.
3. Configuración simplificada de Maven: Spring proporciona archivos POM básicos recomendados para simplificar la configuración de Maven.
4. Configurar Spring automáticamente: Spring Boot configurará automáticamente Spring Framework de acuerdo con las dependencias del proyecto, lo que reduce en gran medida la configuración que utilizará el proyecto.
5. Proporcione funciones listas para producción: Proporcione funciones que se puedan usar directamente en el entorno de producción, como indicadores de rendimiento, información de la aplicación y comprobaciones del estado de la aplicación.
6. Sin generación de código y configuración xml: Spring Boot no genera código. Todas las configuraciones de Spring se pueden realizar sin ninguna configuración xml.
Proceso de inicio de SpringBoot
El inicio de springboot ha pasado por una serie de procesos. Echemos un vistazo al diagrama de flujo del proceso general. No me digas,
hay muchos pasos, pero no importa. Para ayudar que todos entiendan, los números anteriores se explicarán uno por uno de manera popular, dígales a todos de una manera fácil de entender, lo que se ha hecho adentro, no diga tonterías y comience todo el proceso.
1. Ejecute el método SpringApplication.run()
Sin duda, todas las aplicaciones Springboot estándar comienzan desde el método de ejecución
package com.spring;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class App {
public static void main(String[] args) {
// 启动springboot
ConfigurableApplicationContext run = SpringApplication.run(App.class, args);
}
}
Después de ingresar el método de ejecución, se creará un nuevo objeto SpringApplication, y el constructor que crea este objeto ha realizado algunos trabajos preparatorios. Los pasos 2 a 5 del número son lo que se realiza en el constructor.
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified sources using default settings and user supplied arguments.
* @param primarySources the primary sources to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
Además, déjame explicarte que hay tres formas de iniciar SpringBoot. Para conocer otros métodos de inicio, consulta mi otra publicación: Tres formas de iniciar SpringBoot.
2. Determinar el tipo de aplicación
En el método de construcción de SpringApplication, en primer lugar, se usará el método WebApplicationType.deduceFromClasspath() para evaluar el contenedor de la aplicación actual, y el contenedor Servlet se usa de manera predeterminada. Además del servlet, hay NONE y REACTIVE (programación receptiva). );
3. Cargue todos los inicializadores
El inicializador cargado aquí es el propio inicializador de springboot, que se carga desde el archivo de configuración META-INF/spring.factories, entonces, ¿dónde está este archivo? Hay 2 de ellos. Hay un
archivo spring.factories en el proyecto spring-boot-autoconfigure y el proyecto spring-boot del paquete jar del código fuente. Puede ver que la interfaz al principio es org.springframework.context .ApplicationContextInitializer es el inicializador.
Por supuesto, también podemos implementar un inicializador personalizado nosotros mismos: implementar la interfaz ApplicationContextInitializer
MiAplicaciónContextInitializer.java
package com.spring.application;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
/**
* 自定义的初始化器
*/
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
System.out.println("我是初始化的 MyApplicationContextInitializer...");
}
}
Agregue el archivo de configuración META-INF/spring.factories en el directorio de recursos, el contenido es el siguiente y registre el inicializador personalizado;
org.springframework.context.ApplicationContextInitializer=\
com.spring.application.MyApplicationContextInitializer
Luego de iniciar springboot se puede ver el contenido impreso en la consola, aquí podemos ver intuitivamente su secuencia de ejecución, la cual se ejecuta luego de imprimir el banner;
4. Cargar todos los oyentes
La carga del oyente también se carga desde el archivo de configuración META-INF/spring.factories. A diferencia de la inicialización, el oyente carga una clase que implementa la interfaz ApplicationListener. El
oyente personalizado también es el mismo que el inicializador. Está bien, no lo estoy voy a dar un ejemplo aquí;
5. Configure la clase principal del programa para que se ejecute
deduceMainApplicationClass(); Este método es solo para encontrar la clase donde se encuentra el método principal, en preparación para el análisis posterior del paquete, deducir significa inferir, por lo que para ser precisos, la función de este método es inferir la clase donde se encuentra el método principal. se encuentra el método;
6. Inicie el temporizador
Cuando el programa se ejecuta aquí, ha ingresado al cuerpo principal del método de ejecución. El método de ejecución llamado en el primer paso es un método estático. En ese momento, el objeto SpringApplication no ha sido instanciado. El método de ejecución llamado ahora no es estático y necesita ser instanciado. Se puede llamar. Después de ingresar, el temporizador se iniciará primero. ¿Cuál es la función de este temporizador? Como su nombre lo indica, se utiliza para medir el tiempo y calcula cuánto tarda en iniciarse Springboot; el código clave es el siguiente:
// 实例化计时器
StopWatch stopWatch = new StopWatch();
// 开始计时
stopWatch.start();
Captura de pantalla del segmento de código del método de ejecución
7. Establezca java.awt.headless en verdadero
Aquí java.awt.headless se establece en verdadero, lo que significa que se ejecuta en el lado del servidor y aún puede funcionar en el modo sin monitor, mouse y teclado, simulando la función de los dispositivos de entrada y salida.
Después de realizar tal operación, ¿qué quiere hacer SpringBoot? De hecho, quiero configurar la aplicación para permitir que se inicie incluso si no se detecta la pantalla. Para el servidor, no hay necesidad de una pantalla, por lo que debería establecerse así.
El cuerpo del método es el siguiente:
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
A través del método, podemos ver que hay otro getProperty() en el método setProperty(), ¿no es esto innecesario? De hecho, hay 2 parámetros en el método getProperty(), el primer valor clave y el segundo es el valor predeterminado, lo que significa encontrar el valor de la propiedad a través del valor clave. Si el valor de la propiedad está vacío, el valor predeterminado es verdadero. será devuelto, se garantiza que debe haber un caso de valor;
8. Obtenga y habilite el oyente
Este paso implementa la operación básica de inicialización a través del oyente. Este paso hace 2 cosas
- Crea todos los oyentes Spring Run y publica los eventos de inicio de la aplicación
- habilitar oyente
9. Establecer los parámetros de la aplicación
Encapsule los parámetros pasados al ejecutar el método de ejecución en un objeto
Simplemente encapsule los parámetros en un objeto, no hay nada que decir, el constructor del objeto es el siguiente
public DefaultApplicationArguments(String[] args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
Entonces la pregunta es, ¿de dónde viene este parámetro? De hecho, es el parámetro que se pasa al ejecutar el método de ejecución estático en el método principal.
10. Prepara las variables de entorno
Prepare las variables de entorno, incluidas las propiedades del sistema y las propiedades configuradas por el usuario. El bloque de código ejecutado se puede ver después de romper un punto de interrupción en el método prepareEnvironment
. Carga las variables de entorno maven y del sistema.
11. Ignora la información del frijol
Este método configureIgnoreBeanInfo() Este método es establecer el valor predeterminado de spring.beaninfo.ignore en verdadero, lo que significa omitir la búsqueda de beanInfo, y el principio de establecer el valor predeterminado es el mismo que en el paso 7;
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty(
CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
Boolean ignore = environment.getProperty("spring.beaninfo.ignore",
Boolean.class, Boolean.TRUE);
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
ignore.toString());
}
}
Por supuesto, también puede agregar la siguiente configuración al archivo de configuración para configurarlo como falso
spring.beaninfo.ignore=false
Todavía no conozco la función específica de esta configuración, y la agregaré después de que el autor se entere.
12. Imprimir información de banner
Obviamente, este proceso se usa para imprimir el gran banner de primavera en la consola, que es lo siguiente: ¿
Dónde lo imprimió? Lo imprimió en SpringBootBanner.java.Esta clase implementa la interfaz Banner.
Y la información del banner está escrita directamente en el código;
a algunas empresas les gusta personalizar la información del banner, ¿qué debo hacer si quiero cambiarlo a mi ícono favorito? En realidad es muy simple, solo agregue un banner.txt en los recursos. directorio El contenido del archivo txt es el siguiente
_ _
(_) | |
_ _ _____ ___ _ __ __| | ___ _ __ __ _
| | | |/ _ \ \/ / | '_ \ / _` |/ _ \| '_ \ / _` |
| |_| | __/> <| | | | | (_| | (_) | | | | (_| |
\__, |\___/_/\_\_|_| |_|\__,_|\___/|_| |_|\__, |
__/ | __/ |
|___/ |___/
:: yexindong::
Asegúrese de agregarlo al directorio de recursos, no lo agregue mal
, solo necesita agregar un archivo y no necesita hacer nada más, luego inicie Springboot directamente y podrá ver el efecto.
13. Crea el contexto de la aplicación
Cree una instancia del contexto de la aplicación, llame al método createApplicationContext(), aquí hay que usar la reflexión para crear objetos, no hay nada que decir;
14. Crear una instancia del reportero de excepción
El reportero de excepciones se usa para capturar excepciones globales. Cuando ocurre una excepción en la aplicación springboot, el reportero de excepciones la capturará y la manejará en consecuencia. El reportero de excepciones predeterminado está configurado en el archivo spring.factories.
Cabe señalar que este informador de excepciones solo detectará la excepción lanzada durante el proceso de inicio. Si se informa un error en la solicitud del usuario después de que se complete el inicio, el informador de excepciones no detectará la excepción que se produce en la solicitud. Ahora que entiendes el principio,
a continuación configuramos un reportero de excepción para jugar con nosotros mismos;
MyExceptionReporter.java hereda la interfaz SpringBootExceptionReporter
package com.spring.application;
import org.springframework.boot.SpringBootExceptionReporter;
import org.springframework.context.ConfigurableApplicationContext;
public class MyExceptionReporter implements SpringBootExceptionReporter {
private ConfigurableApplicationContext context;
// 必须要有一个有参的构造函数,否则启动会报错
MyExceptionReporter(ConfigurableApplicationContext context) {
this.context = context;
}
@Override
public boolean reportException(Throwable failure) {
System.out.println("进入异常报告器");
failure.printStackTrace();
// 返回false会打印详细springboot错误信息,返回true则只打印异常信息
return false;
}
}
Registre el reportero de excepciones en el archivo spring.factories
# Error Reporters 异常报告器
org.springframework.boot.SpringBootExceptionReporter=\
com.spring.application.MyExceptionReporter
Luego configuramos el número de puerto en un valor grande en application.yml, lo que definitivamente causará un error.
server:
port: 80828888
Después del inicio, la consola imprime la siguiente imagen
15. Prepara el contexto
El entorno de contexto preparado aquí es para prepararse para la próxima actualización, y se realizan algunas cosas adicionales en él;
15.1 Generador BeanName para instanciar singletons
Dentro del método postProcessApplicationContext(context); El objeto BeanNameGenerator se crea utilizando el modo singleton, que en realidad es el generador beanName utilizado para generar el nombre del objeto bean.
15.2 Ejecutar el método de inicialización
¿Cuáles son los métodos de inicialización? ¿Recuerdas el inicializador cargado en el paso 3? De hecho, todos los inicializadores cargados en el paso 3 se ejecutan y la clase que implementa la interfaz ApplicationContextInitializer
15.3 Registrar parámetros de inicio en el contenedor
Aquí, los parámetros de inicio se registran en el contenedor en modo singleton para conveniencia futura.El beanName del parámetro es: springApplicationArguments
16. Actualizar el contexto
La actualización del contexto ya se encuentra en la categoría de resorte. El ensamblaje automático y el inicio de Tomcat se completan en este método. Hay otros mecanismos integrados en resorte que no se detallarán aquí.
17. Posprocesamiento del contexto de actualización
El método afterRefresh es un procesamiento posterior al inicio, que está reservado para la expansión del usuario. Actualmente, este método está vacío.
/**
* Called after the context has been refreshed.
* @param context the application context
* @param args the application arguments
*/
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
}
18. Fin del temporizador
En este punto, Springboot realmente se ha completado y el temporizador imprimirá la hora para iniciar Springboot.El
inicio sigue siendo muy rápido como se ve en la consola, y el inicio se completa en menos de 2 segundos;
19. Publicar evento listo para el contexto
Dile a la aplicación que estoy listo para ir a trabajar
20. Ejecutar un método de ejecución personalizado
Esta es una función de extensión, callRunners(context, applicationArguments) puede ejecutar un método de ejecución personalizado después de que se complete el inicio; hay 2 formas de lograrlo:
- Implementar la interfaz ApplicationRunner
- Implementar la interfaz CommandLineRunner
A continuación, verifiquemos que, para facilitar la legibilidad del código, puse estos dos métodos en la misma clase
package com.spring.init;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
/**
* 自定义run方法的2种方式
*/
@Component
public class MyRunner implements ApplicationRunner, CommandLineRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(" 我是自定义的run方法1,实现 ApplicationRunner 接口既可运行" );
}
@Override
public void run(String... args) throws Exception {
System.out.println(" 我是自定义的run方法2,实现 CommandLineRunner 接口既可运行" );
}
}
Después de iniciar springboot, puede ver la información impresa en la consola
encima
De hecho, es bueno que los desarrolladores entiendan el principio del inicio de springboot. Al menos sabes qué se puede expandir, cómo expandir y cómo son sus principios internos. Creo que después de comprender estas ideas, déjate escribir un springboot tú mismo. También es posible, pero aquí hay solo una lista del proceso de inicio, no todos los involucrados, el código fuente es muy complicado, recuerdo que una vaca grande dijo: "Cuando miramos el código fuente, solo podemos adivinar cuál es el autor piensa por asociación o, y tenga cuidado de verificar, al igual que cuando aprendimos poemas antiguos cuando éramos jóvenes, solo podemos adivinar los pensamientos de los antiguos.Tomando el Tao Te King como ejemplo, todos tienen opiniones diferentes después de leerlo , que requiere opiniones diferentes”;