Cuando desarrollemos cualquier proyecto de Spring Boot, usaremos las siguientes clases de inicio
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Como se puede ver en el código anterior, la definición de anotación ( @SpringBootApplication
) y la definición de clase ( SpringApplication.run
) son las más deslumbrantes, por lo que para descubrir el misterio de SpringBoot, debemos comenzar con estas dos.
1. El secreto detrás de SpringBootApplication
La anotación @SpringBootApplication es la anotación principal de Spring Boot, que en realidad es una anotación combinada:
@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 {
...
}
Aunque la definición usa múltiples Anotaciones para anotar la información original, de hecho solo tres Anotaciones son importantes:
-
@Configuration
(@SpringBootConfiguration
Haga clic para ver y encontrar que todavía se aplica@Configuration
) -
@EnableAutoConfiguration
-
@ComponentScan
Eso es @SpringBootApplication
= (atributo predeterminado) @Configuration
+ @EnableAutoConfiguration
+ @ComponentScan
.
Por lo tanto, si usamos la siguiente clase de inicio SpringBoot, toda la aplicación SpringBoot aún puede ser funcionalmente equivalente a la clase de inicio anterior:
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Es agotador escribir estos 3 cada vez, por lo que @SpringBootApplication
es conveniente escribir uno. A continuación, las tres Anotaciones se introducen por separado.
1, @Configuración
Esto @Configuration
no nos es desconocido. Es el que usa la clase de configuración del contenedor Spring Ioc en forma de JavaConfig @Configuration
. La comunidad SpringBoot recomienda usar el formulario de configuración basado en JavaConfig. Por lo tanto, después de marcar la clase de inicio aquí, @Configuration
se es en realidad un contenedor IoC clase de configuración.
Para dar algunos ejemplos simples, revise la diferencia entre los métodos de configuración XML y config:
(1) Nivel de expresión
La configuración basada en XML es la siguiente:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
default-lazy-init="true">
<!--bean定义-->
</beans>
El método de configuración basado en JavaConfig es el siguiente:
@Configuration
public class MockConfiguration{
//bean定义
}
Cualquier @Configuration
definición de clase Java anotada es una clase de configuración JavaConfig.
(2) Nivel de definición del frijol de registro
La configuración basada en XML se ve así:
<bean id="mockService" class="..MockServiceImpl">
...
</bean>
El formulario de configuración basado en JavaConfig es el siguiente:
@Configuration
public class MockConfiguration{
@Bean
public MockService mockService(){
return new MockServiceImpl();
}
}
Para cualquier @Bean
método marcado, su valor de retorno se registrará como una definición de bean en el contenedor IoC de Spring, y el nombre del método será el id de la definición de bean por defecto.
(3) Nivel de relación de inyección de dependencia expresa
Para expresar la relación de dependencia entre beans y beans, generalmente es así en formato XML:
<bean id="mockService" class="..MockServiceImpl">
<propery name ="dependencyService" ref="dependencyService" />
</bean>
<bean id="dependencyService" class="DependencyServiceImpl"></bean>
El formulario de configuración basado en JavaConfig es el siguiente:
@Configuration
public class MockConfiguration{
@Bean
public MockService mockService(){
return new MockServiceImpl(dependencyService());
}
@Bean
public DependencyService dependencyService(){
return new DependencyServiceImpl();
}
}
Si la definición de un bean depende de otros beans, puede llamar directamente al método de creación del bean dependiente en la clase JavaConfig correspondiente.
@Configuration
: Cuando lo mencionas, @Configuration
tienes que mencionar a su pareja @Bean
. Usando estas dos anotaciones, puede crear una clase de configuración de resorte simple que se puede usar para reemplazar el archivo de configuración xml correspondiente.
<beans>
<bean id = "car" class="com.test.Car">
<property name="wheel" ref = "wheel"></property>
</bean>
<bean id = "wheel" class="com.test.Wheel"></bean>
</beans>
Equivalente a:
@Configuration
public class Conf {
@Bean
public Car car() {
Car car = new Car();
car.setWheel(wheel());
return car;
}
@Bean
public Wheel wheel() {
return new Wheel();
}
}
@Configuration
La clase anotada identifica que esta clase puede usar el contenedor Spring IoC como fuente de definiciones de beans.
@Bean
La anotación le dice a Spring que un método anotado con @Bean devolverá un objeto que debe registrarse como un bean en el contexto de la aplicación Spring.
2, @ Escaneo de componentes
@ComponentScan
Esta anotación es muy importante en Spring. Corresponde a los elementos en la configuración XML. @ComponentScan
Su función es escanear y cargar automáticamente componentes calificados (como @Component
y @Repository
etc.) o definiciones de bean, y finalmente cargar estas definiciones de bean en el contenedor IoC.
Podemos personalizar con precisión el alcance del escaneo automático a través de atributos como basePackages @ComponentScan
Si no se especifica, la implementación predeterminada del marco Spring escaneará @ComponentScan
desde el paquete donde se declara la clase.
Nota: Por lo tanto, la clase de inicio de SpringBoot se coloca mejor bajo el paquete raíz, porque basePackages no se especifica de manera predeterminada.
3, @EnableAutoConfiguration
Personalmente siento que @EnableAutoConfiguration
esta Anotación es la más importante, así que la interpretaré al final. ¿Aún recuerdas la @Enable
definición de Anotación con varios nombres proporcionada por el framework Spring? Por @EnableScheduling、@EnableCaching、@EnableMBeanExport
ejemplo, @EnableAutoConfiguration
el concepto y la forma de hacer las cosas en realidad están en la misma línea.. Un breve resumen es que, con la ayuda @Import
de soporte, recopile y registre definiciones de frijoles relacionadas con escenarios específicos.
@EnableScheduling
Es para cargar todas las definiciones de beans relacionadas con el marco de programación de Spring en el contenedor IoC a través de @Import.
@EnableMBeanExport
Es cargar definiciones de beans relacionadas con JMX en el contenedor IoC a través de @Import.
Pero @EnableAutoConfiguration
con la ayuda de @Import, todas las definiciones de beans que cumplen las condiciones de configuración automática se cargan en el contenedor IoC, ¡eso es todo!
@EnableAutoConfiguration
El proyecto se configurará automáticamente de acuerdo con las dependencias de jar en la ruta de clase. Por ejemplo, si se agregan dependencias spring-boot-starter-web
, las dependencias de Tomcat y Spring MVC se agregarán automáticamente, y Spring Boot configurará automáticamente Tomcat y Spring MVC.
Como anotación compuesta, @EnableAutoConfiguration define la información clave de la siguiente manera:
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
Entre ellos, lo más importante es usar el contenedor IoC @Import(EnableAutoConfigurationImportSelector.class)
que EnableAutoConfigurationImportSelector,@EnableAutoConfiguration
puede ayudar a la aplicación SpringBoot a cargar todas @Configuration
las configuraciones elegibles en la creación y el uso actual de SpringBoot. SpringFactoriesLoader
Como un "pulpo", con el apoyo de una clase de herramienta original del marco Spring: ¡ @EnableAutoConfiguration
se puede lograr la función de configuración automática inteligente!
Configure automáticamente los héroes detrás de escena: SpringFactoriesLoader en detalle
SpringFactoriesLoader es un esquema de extensión privado del framework Spring, y su función principal es cargar la configuración desde el archivo de configuración especificado META-INF/spring.factories
.
public abstract class SpringFactoriesLoader {
//...
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
...
}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
....
}
}
Si se usa en conjunto @EnableAutoConfiguration
, proporciona un soporte más funcional para la búsqueda de configuración, es decir, de acuerdo con el @EnableAutoConfiguration
nombre de clase completo de la clase org.springframework.boot.autoconfigure.EnableAutoConfiguration
como clave de búsqueda, @Configuration
se puede obtener un conjunto de clases correspondiente.
La imagen de arriba es META-INF/spring.factories
un extracto del archivo de configuración en el paquete de dependencia de configuración automática de SpringBoot, que puede ilustrar bien el problema.
Por lo tanto, @EnableAutoConfiguration
el caballero mágico de la configuración automática se convierte en: buscar todos META-INF/spring.factories
los archivos de configuración desde el classpath e org.springframework.boot.autoconfigure.EnableutoConfiguration
instanciar los elementos de configuración correspondientes en la @Configuration
clase de configuración del contenedor IoC correspondiente en forma de JavaConfig marcado a través de la reflexión (Java Refletion), luego se agrega en uno y cargado en el contenedor IoC.
2. Exploración en profundidad del proceso de ejecución de SpringApplication
La implementación del método de ejecución de SpringApplication es la ruta principal de nuestro viaje. El proceso principal de este método se puede resumir aproximadamente de la siguiente manera:
1) Si estamos utilizando el método de ejecución estático de SpringApplication, entonces, en este método, primero debemos crear una instancia de objeto SpringApplication y luego llamar al método de instancia de SpringApplication creado. Cuando se inicializa la instancia de SpringApplication, hará varias cosas por adelantado:
-
Según si hay una clase característica en el classpath,
org.springframework.web.context.ConfigurableWebApplicationContext
se determina si se debe crear un tipo ApplicationContext para aplicaciones Web. -
El uso
SpringFactoriesLoader
busca y carga todos los disponibles en el classpath de la aplicaciónApplicationContextInitializer
. -
El uso
SpringFactoriesLoader
busca y carga todos los disponibles en el classpath de la aplicaciónApplicationListener
. -
Inferir y establecer la clase definitoria del método principal.
2) Después de que se completa la inicialización de la instancia de SpringApplication y se completa la configuración, la lógica del método de ejecución comienza a ejecutarse. Al comienzo de la ejecución del método, primero atraviesa y ejecuta todos los métodos que se pueden encontrar y cargar SpringFactoriesLoader
. SpringApplicationRunListener
. Llame a sus started()
métodos para decirles SpringApplicationRunListener
: "¡Oye, la aplicación SpringBoot está a punto de comenzar a ejecutarse!".
3) Cree y configure el entorno que utilizará la aplicación Spring Boot actual (incluida la configuración de PropertySource y el perfil que se utilizará).
4) Atraviese y llame a todos SpringApplicationRunListener
los environmentPrepared()
métodos y dígales: "¡El entorno utilizado por la aplicación SpringBoot actual está listo!".
5) Si la propiedad showBanner de SpringApplication se establece en verdadero, imprima el banner.
6) Según si el usuario ha establecido explícitamente applicationContextClass
el tipo y el resultado de la inferencia de la fase de inicialización, decida qué tipo crear para la aplicación SpringBoot actual ApplicationContext
y complete la creación, y luego decida si agregar ShutdownHook de acuerdo con las condiciones, decida si para usar uno personalizado BeanNameGenerator
, y decidir si usar uno personalizado Por ResourceLoader
supuesto, lo más importante es configurar el Entorno previamente preparado para el creado ApplicationContext
.
7) Después de que se crea ApplicationContext, SpringApplication lo usará nuevamente Spring-FactoriesLoader
para buscar y cargar todos los disponibles en classpath ApplicationContext-Initializer
, y luego atravesará y llamará a estos métodos ApplicationContextInitializer
( applicationContext) para procesar aún más initialize
los creados .ApplicationContext
8) Atraviesa y llama a todos SpringApplicationRunListener
los métodos contextPrepared()
.
9) El paso principal es @EnableAutoConfiguration
cargar todas las configuraciones obtenidas antes y otras formas de configuraciones de contenedores de IoC en la configuración preparada ApplicationContext
.
10) Atraviesa y llama a todos SpringApplicationRunListener
los métodos contextLoaded()
.
11) El método llamado ApplicationContext
para refresh()
completar el último proceso disponible para el contenedor IoC.
12) Averiguar ApplicationContext
si existen registros en el sistema actual CommandLineRunner
, y en caso afirmativo recorrerlos y ejecutarlos.
13) En circunstancias normales, atraviese el SpringApplicationRunListener
método de ejecución finished()
(si ocurre una excepción en todo el proceso, se seguirán llamando a todos los métodos SpringApplicationRunListener
, finished()
pero en este caso, la información de la excepción se pasará para su procesamiento)
Después de eliminar el punto de notificación de eventos, todo el proceso es el siguiente:
Este artículo toma como ejemplo la depuración de un programa de inicio SpringBoot real y analiza su lógica de inicio y los principios de configuración automática con referencia al diagrama de clase principal en el proceso.
Descripción general:
La imagen de arriba muestra el diagrama de la estructura de inicio de SpringBoot. Descubrimos que el proceso de inicio se divide principalmente en tres partes:
-
La primera parte es inicializar el módulo de SpringApplication y configurar algunas variables de entorno básicas, recursos, constructores y oyentes;
-
La segunda parte implementa el esquema de inicio específico de la aplicación, incluido el módulo de monitoreo del proceso de inicio, el módulo del entorno de configuración de carga y el módulo de contexto de creación del núcleo;
-
La tercera parte es el módulo de configuración automática, que es el núcleo de la configuración automática de springboot y se discutirá en detalle en el siguiente análisis. En la siguiente rutina de inicio, conectaremos las funciones principales en la estructura.
puesta en marcha:
Cada programa SpringBoot tiene una entrada principal, que es el método principal, que llama e inicia SpringApplication.run()
todo el programa spring-boot. La clase donde se encuentra el método necesita usar @SpringBootApplication
anotaciones y @ImportResource
anotaciones (si es necesario), @SpringBootApplication
incluidas tres anotaciones, las funciones son como sigue:
-
@EnableAutoConfiguration
: SpringBoot configura automáticamente Spring Framework en función de las dependencias declaradas por la aplicación. -
@SpringBootConfiguration
(Interno@Configuration
): la clase marcada es igual a (applicationContext.xml
) en el archivo de configuración Spring XML, ensamblando todas las transacciones de beans y proporcionando un contexto Spring. -
@ComponentScan
: Escaneo de componentes, que puede descubrir y ensamblar beans automáticamente. De manera predeterminada, se escanean los archivos debajo de la ruta del paquete en el método de ejecución de SpringApplicationBooter.class
, por lo que es mejor colocar la clase de inicio en la ruta del paquete raíz.
Clase de inicio de SpringBoot
Primero ingrese el método de ejecución
En el método de ejecución, se crea una instancia de SpringApplication.En este método de construcción, podemos encontrar que llama a un método de inicialización inicializado.
Esto es principalmente para asignar algunos valores iniciales al objeto SpringApplication. Después de ejecutar el constructor, volvemos al método de ejecución
Los siguientes pasos clave se implementan en este método:
1. Cree un detector de aplicaciones SpringApplicationRunListeners
y comience a escuchar
2. Cargue el entorno de configuración de SpringBoot ( ConfigurableEnvironment
), si se publica a través del contenedor web, se cargará StandardEnvironment
y eventualmente se heredará ConfigurableEnvironment
, el diagrama de clases es el siguiente
Se puede ver que *Environment finalmente implementa la interfaz PropertyResolver.Cuando generalmente obtenemos el método de valor correspondiente a la clave especificada en el archivo de configuración a través del objeto de entorno, llamamos al método getProperty de la interfaz propertyResolver.
3. El entorno de configuración ( Environment
) se agrega al objeto de escucha ( SpringApplicationRunListeners
)
4. Cree el objeto de retorno del método de ejecución: ConfigurableApplicationContext
(contexto de configuración de la aplicación), podemos ver el método de creación:
El método primero obtendrá el contexto de aplicación establecido explícitamente ( applicationContextClass
), si no existe, luego cargará la configuración de entorno predeterminada (juzgando si lo es web environment
), seleccionará AnnotationConfigApplicationContext
el contexto de anotación predeterminado (cargará beans escaneando todas las clases de anotación) y finalmente crea una instancia a través de BeanUtils del objeto de contexto y devuélvelo.
El diagrama de clases de ConfigurableApplicationContext es el siguiente:
Depende principalmente de las dos direcciones de su herencia:
-
Ciclo de vida: clase de ciclo de vida, que define inicio inicio, fin de parada, está en ejecución si se ejecuta el método de valor nulo del ciclo de vida medio
-
ApplicationContext: clase de contexto de aplicación, que hereda principalmente beanFactory (clase de fábrica de frijoles)
5. De vuelta en el método de ejecución, el método prepareContext listeners、environment、applicationArguments、banner
asocia otros componentes importantes con el objeto de contexto.
6. El siguiente refreshContext(context)
método (el método de inicialización es el siguiente) será spring-boot-starter-*
la clave para realizar la configuración automática (mybatis, redis, etc.), incluido spring.factories
el trabajo central de carga, creación de instancias de beans, etc.
Después de la configuración, Springboot realizó un trabajo de acabado básico y devolvió el contexto del entorno de la aplicación. Mirando hacia atrás en el proceso general, el inicio de Springboot crea principalmente el entorno de configuración (entorno), los detectores de eventos (escuchas) y el contexto de la aplicación (applicationContext) y, en función de las condiciones anteriores, comenzamos a crear instancias de los beans que necesitamos en el contenedor. Hasta ahora, a través del inicio de SpringBoot El programa ha sido construido A continuación, analicemos cómo realizar la configuración automática.
Configuración automática:
En el diagrama de estructura de inicio anterior, notamos que tanto la inicialización de la aplicación como el proceso de ejecución específico invocaron el módulo de configuración automática SpringBoot.
Módulo de configuración automática SpringBoot
El uso principal de este módulo de configuración SpringFactoriesLoader
es el cargador de fábrica de Spring. Este objeto proporciona loadFactoryNames
métodos. Los parámetros de entrada son factoryClass y classLoader, es decir, se debe pasar el nombre de la clase de fábrica en la figura anterior y el cargador de clases correspondiente. El método se basará en el classLoader especificado, cargará el archivo especificado en la ruta de búsqueda del sumador de clases, es decir, spring.factories
el archivo, la clase de fábrica entrante es la interfaz y la clase correspondiente en el archivo es la clase de implementación del interfaz, o finalmente como la clase de implementación, por lo que el archivo generalmente es el siguiente Este tipo de colección de nombres de clase de uno a muchos, después de obtener los nombres de clase de estas clases de implementación, el método devuelve la colección de nombres de clase y el llamador del loadFactoryNames
método obtiene estas colecciones, y luego obtiene los objetos de clase y los métodos de construcción de estas clases a través de la reflexión, y finalmente genera una instancia.
Interfaz de fábrica y varios nombres de interfaz de clase de implementación
La siguiente figura nos ayuda a visualizar el proceso de configuración automática.
Diagrama de relación de componentes clave de configuración automática de SpringBoot
mybatis-spring-boot-starter
, spring-boot-starter-web
y los archivos META-INF de otros componentes contienen spring.factories
archivos. En el módulo de configuración automática, SpringFactoriesLoader
se recopila el nombre completo de la clase en el archivo y se devuelve una matriz del nombre completo de la clase. El nombre completo devuelto de la clase es instanciado a través de la reflexión, formando una instancia específica de The factory, la instancia de fábrica para generar los beans que el componente necesita específicamente.
Mencionamos EnableAutoConfiguration
anotaciones antes, y su diagrama de clases es el siguiente:
Se puede encontrar que finalmente implementa ImportSelector
(selector) y BeanClassLoaderAware
(bean class loader middleware), centrándose en los siguientes AutoConfigurationImportSelector
métodos selectImports
.
[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo de enlace antirrobo, se recomienda guardar la imagen y cargarla directamente (img-Dm6tiUWw-1597051375071) (https://upload-images.jianshu.io/ upload_images/18688925-97932faefd1184cf?imageMogr2 /orientación automática/strip%7CimageView2/2/w/1240)]
Este método se ejecuta antes del proceso de inicio de springboot: creación de instancias de beans y devuelve una lista de información de clase para crear instancias. Sabemos que si se obtiene la información de la clase, Spring puede cargar naturalmente la clase en el jvm a través del cargador de clases Ahora que hemos confiado en los componentes que necesitamos a través de la dependencia del iniciador Spring-Boot, la información de clase de estos componentes está en el método seleccionado También se puede obtener, no se preocupe, sigamos analizando hacia abajo.
El método en este método getCandidateConfigurations
, aprendido a través de la anotación del método, devuelve una lista de nombres de clase de la clase de configuración automática, el método llama al loadFactoryNames
método, ver el método
En el código anterior, puede ver que el configurador automático encontrará la clave correspondiente en factoryClass.getName()
todos spring.factories
los archivos bajo la ruta del sistema del proyecto pasada, para cargar las clases dentro. Seleccionaremos el archivo mybatis-spring-boot-autoconfigure
bajo estespring.factories
Ingresando org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
, mira principalmente el encabezado de la clase:
Descubrí que Spring @Configuration
es como un springBean marcado con anotaciones, continúe mirando hacia abajo,
-
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class})
: cuando estas dos clases existenSqlSessionFactory.class
, la clase de configuración se analizará; de lo contrario, esta clase de configuración no se analizará, tiene sentido, necesitamos que mybatis nos devuelva el objeto de sesión y debe haber clases relacionadas con la fábrica de sesiones.SqlSessionFactoryBean.class
MybatisAutoConfiguration
-
@CondtionalOnBean(DataSource.class)
: Trate solo con fuentes de datos que hayan sido declaradas como beans. -
@ConditionalOnMissingBean(MapperFactoryBean.class)
Esta anotación significa que si el bean especificado por nombre no existe en el contenedor, se creará la inyección de bean; de lo contrario, no se ejecutará (el código fuente de esta clase es largo y el límite de espacio no se pega por completo)
La configuración anterior puede garantizar sqlSessionFactory、sqlSessionTemplate、dataSource
que los componentes requeridos por mybatis se puedan configurar automáticamente. @Configuration
La anotación ha proporcionado el contexto de Spring, por lo que el método de configuración de los componentes anteriores tiene el mismo efecto que la configuración a través del archivo mybatis.xml cuando se inicia Spring.
A través del análisis, podemos encontrar que siempre que exista una ruta de clase basada en el proyecto SpringBoot y el dataSourceBean se haya registrado en el contenedor SqlSessionFactory.class
, SqlSessionFactoryBean.class
se puede activar la configuración automática, lo que significa que solo necesitamos agregar varias dependencias requeridas por mybatis para el proyecto maven Se puede activar la configuración automática, pero si se introduce la dependencia nativa de mybatis, la clase de configuración automática debe modificarse para cada función integrada, por lo que no se obtendrá el efecto listo para usar.
Entonces, Spring-boot nos proporciona un iniciador unificado que puede configurar directamente las clases relacionadas, y las dependencias (mybatis) requeridas para activar la configuración automática son las siguientes:
Aquí están mybatis-spring-boot-starter
todas las dependencias en el archivo pom.xml en el código fuente interceptado:
Debido a la naturaleza transitiva de las dependencias de maven, podemos confiar en todas las clases que deben configurarse automáticamente, siempre que confiemos en el iniciador para lograr funciones listas para usar. También muestra que Springboot simplifica la gran cantidad de configuración XML y la gestión de dependencias complejas que trae Spring Framework, lo que permite a los desarrolladores prestar más atención al desarrollo de la lógica empresarial.
por fin
Atentos a la cuenta oficial: Programador Chasing the Wind. Responda 003 Obtenga el último manual de preguntas de la entrevista Java 2020 (más de 200 páginas de documentos PDF)