Quando desenvolvemos qualquer projeto Spring Boot, usaremos as seguintes classes de inicialização
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Como pode ser visto no código acima, a definição de anotação ( @SpringBootApplication
) e a definição de classe ( SpringApplication.run
) são as mais deslumbrantes, portanto, para descobrir o mistério do SpringBoot, precisamos começar com essas duas.
1. O segredo por trás do SpringBootApplication
A anotação @SpringBootApplication é a anotação principal do Spring Boot, que na verdade é uma anotação 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 {
...
}
Embora a definição use várias Anotações para anotar as informações originais, na verdade apenas três Anotações são importantes:
-
@Configuration
(@SpringBootConfiguration
Clique para ver e descobrir que ainda é aplicado@Configuration
) -
@EnableAutoConfiguration
-
@ComponentScan
Ou seja @SpringBootApplication
= (atributo padrão) @Configuration
+ @EnableAutoConfiguration
+ @ComponentScan
.
Portanto, se usarmos a seguinte classe de inicialização SpringBoot, todo o aplicativo SpringBoot ainda pode ser funcionalmente equivalente à classe de inicialização anterior:
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
É cansativo escrever esses 3 a cada vez, então @SpringBootApplication
é conveniente escrever um. A seguir, as três Anotações são apresentadas separadamente.
1、@Configuração
Isso @Configuration
não é desconhecido para nós. É aquele usado pela classe de configuração do contêiner Spring Ioc na forma de JavaConfig @Configuration
. A comunidade SpringBoot recomenda o uso do formulário de configuração baseado em JavaConfig. Portanto, após a classe de inicialização aqui ser marcada, @Configuration
ela é, na verdade, um contêiner IoC. classe de configuração.
Para dar alguns exemplos simples, revise a diferença entre XML e métodos de configuração de configuração:
(1) Nível de expressão
A configuração baseada em XML é a seguinte:
<?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>
O método de configuração baseado em JavaConfig é o seguinte:
@Configuration
public class MockConfiguration{
//bean定义
}
Qualquer @Configuration
definição de classe Java anotada é uma classe de configuração JavaConfig.
(2) Nível de definição do bean de registro
A configuração baseada em XML se parece com isto:
<bean id="mockService" class="..MockServiceImpl">
...
</bean>
O formulário de configuração baseado no JavaConfig é o seguinte:
@Configuration
public class MockConfiguration{
@Bean
public MockService mockService(){
return new MockServiceImpl();
}
}
Para qualquer @Bean
método marcado, seu valor de retorno será registrado como uma definição de bean no contêiner IoC do Spring, e o nome do método será padronizado para o id da definição do bean.
(3) Nível de relação de injeção de dependência expressa
Para expressar a relação de dependência entre beans e beans, geralmente é assim na forma XML:
<bean id="mockService" class="..MockServiceImpl">
<propery name ="dependencyService" ref="dependencyService" />
</bean>
<bean id="dependencyService" class="DependencyServiceImpl"></bean>
O formulário de configuração baseado no JavaConfig é o seguinte:
@Configuration
public class MockConfiguration{
@Bean
public MockService mockService(){
return new MockServiceImpl(dependencyService());
}
@Bean
public DependencyService dependencyService(){
return new DependencyServiceImpl();
}
}
Se a definição de um bean depende de outros beans, você pode chamar diretamente o método de criação do bean dependente na classe JavaConfig correspondente.
@Configuration
: Quando você menciona isso, @Configuration
você tem que mencionar o parceiro dele @Bean
. Usando essas duas anotações, você pode criar uma classe de configuração de primavera simples que pode ser usada para substituir o arquivo de configuração xml correspondente.
<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
A classe anotada identifica que esta classe pode usar o contêiner Spring IoC como uma fonte de definições de bean.
@Bean
A anotação informa ao Spring que um método anotado com @Bean retornará um objeto que deve ser registrado como um bean no contexto do aplicativo Spring.
2、@ComponentScan
@ComponentScan
Esta anotação é muito importante no Spring. Corresponde aos elementos na configuração XML. @ComponentScan
Sua função é verificar e carregar automaticamente componentes qualificados (como @Component
e @Repository
etc.) ou definições de bean e, finalmente, carregar essas definições de bean no contêiner IoC.
Podemos personalizar minuciosamente o escopo da verificação automática por meio de atributos como basePackages @ComponentScan
.Se não for especificado, a implementação padrão da estrutura Spring fará @ComponentScan
a varredura do pacote em que a classe é declarada.
Nota: Portanto, a classe de inicialização do SpringBoot é melhor colocada no pacote raiz, porque basePackages não é especificado por padrão.
3、@EnableAutoConfiguration
Pessoalmente, sinto que @EnableAutoConfiguration
esta Annotation é a mais importante, por isso vou interpretá-la no final.Você ainda se lembra da @Enable
definição de Annotation com vários nomes fornecidos pelo framework Spring? Por @EnableScheduling、@EnableCaching、@EnableMBeanExport
exemplo, @EnableAutoConfiguration
o conceito e a maneira de fazer as coisas estão na mesma linha.Um breve resumo é que, com a ajuda @Import
do suporte, colete e registre definições de bean relacionadas a cenários específicos.
@EnableScheduling
É para carregar todas as definições de bean relacionadas à estrutura de agendamento Spring no contêiner IoC por meio de @Import.
@EnableMBeanExport
É para carregar as definições de bean relacionadas ao JMX no contêiner IoC por meio de @Import.
Mas @EnableAutoConfiguration
com a ajuda de @Import, todas as definições de bean que atendem às condições de configuração automática são carregadas no contêiner IoC, isso é tudo!
@EnableAutoConfiguration
O projeto será configurado automaticamente de acordo com as dependências do jar no caminho da classe. Por exemplo, se forem adicionadas dependências spring-boot-starter-web
, as dependências do Tomcat e do Spring MVC serão adicionadas automaticamente e o Spring Boot configurará automaticamente o Tomcat e o Spring MVC.
Como uma anotação composta, @EnableAutoConfiguration define as informações principais da seguinte forma:
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
Entre eles, o mais importante é usar o contêiner IoC @Import(EnableAutoConfigurationImportSelector.class)
que EnableAutoConfigurationImportSelector,@EnableAutoConfiguration
pode ajudar o aplicativo SpringBoot a carregar todas as @Configuration
configurações elegíveis na criação e uso atuais do SpringBoot. SpringFactoriesLoader
Assim como um "polvo", com o suporte de uma classe de ferramenta original do framework Spring: a @EnableAutoConfiguration
função de configuração automática inteligente pode ser realizada!
Configure automaticamente os heróis dos bastidores: SpringFactoryLoader em detalhes
SpringFactoryLoader é um esquema de extensão privado do framework Spring, e sua função principal é carregar a configuração do arquivo de configuração 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) {
....
}
}
Se for usado em conjunto @EnableAutoConfiguration
, fornece suporte mais funcional para pesquisa de configuração, ou seja, de acordo com o @EnableAutoConfiguration
nome completo da classe org.springframework.boot.autoconfigure.EnableAutoConfiguration
como chave de pesquisa, um conjunto correspondente de @Configuration
classes pode ser obtido.
A imagem acima é META-INF/spring.factories
um trecho do arquivo de configuração no pacote de dependência autoconfigure do SpringBoot, que pode ilustrar bem o problema.
Portanto, @EnableAutoConfiguration
o cavaleiro mágico da configuração automática torna-se: pesquisar todos os META-INF/spring.factories
arquivos de configuração do caminho de classe e org.springframework.boot.autoconfigure.EnableutoConfiguration
instanciar os itens de configuração correspondentes na @Configuration
classe de configuração do contêiner IoC correspondente na forma de JavaConfig marcada por reflexão (Java Refletion). e carregado no contêiner IoC.
2. Exploração aprofundada do processo de execução do SpringApplication
A implementação do método run do SpringApplication é a principal rota de nossa jornada. O processo principal deste método pode ser resumido da seguinte forma:
1) Se estivermos usando o método de execução estático de SpringApplication, nesse método, devemos primeiro criar uma instância do objeto SpringApplication e, em seguida, chamar o método de instância do SpringApplication criado. Quando a instância SpringApplication é inicializada, ela fará várias coisas com antecedência:
-
De acordo com a existência ou não de uma classe característica no caminho de classe,
org.springframework.web.context.ConfigurableWebApplicationContext
é determinado se um tipo ApplicationContext para aplicativos da Web deve ser criado. -
Use
SpringFactoriesLoader
localiza e carrega todos os disponíveis no classpath do aplicativoApplicationContextInitializer
. -
Use
SpringFactoriesLoader
localiza e carrega todos os disponíveis no classpath do aplicativoApplicationListener
. -
Inferir e definir a classe de definição do método principal.
2) Após concluída a inicialização da instância SpringApplication e as configurações concluídas, a lógica do método run começa a ser executada. No início da execução do método, ele primeiro percorre e executa todos os métodos que podem ser encontrados e SpringFactoriesLoader
carregados SpringApplicationRunListener
. Chame seus started()
métodos para dizer a eles SpringApplicationRunListener
: "Ei, o aplicativo SpringBoot está prestes a começar a ser executado!".
3) Crie e configure o Ambiente a ser usado pelo aplicativo Spring Boot atual (incluindo a configuração da PropertySource e do Profile a serem usados).
4) Percorra e chame todos SpringApplicationRunListener
os environmentPrepared()
métodos e diga a eles: "O ambiente usado pelo aplicativo SpringBoot atual está pronto!".
5) Se a propriedade showBanner de SpringApplication estiver configurada para true, imprima o banner.
6) De acordo com se o usuário definiu explicitamente applicationContextClass
o tipo e o resultado da inferência da fase de inicialização, decida qual tipo criar para o aplicativo SpringBoot atual ApplicationContext
e conclua a criação e, em seguida, decida se deseja adicionar ShutdownHook de acordo com as condições, decida se usar um customizado BeanNameGenerator
, e decidir se vai usar um customizado Claro ResourceLoader
, o mais importante é ajustar o Ambiente previamente preparado ao criado ApplicationContext
.
7) Depois que o ApplicationContext é criado, o SpringApplication irá usá-lo novamente Spring-FactoriesLoader
para encontrar e carregar todos os disponíveis no classpath ApplicationContext-Initializer
e, em seguida, percorrer e chamar esses métodos ApplicationContextInitializer
( applicationContext) para processar posteriormente initialize
os criados .ApplicationContext
8) Atravesse e chame todos SpringApplicationRunListener
os métodos contextPrepared()
.
9) A etapa principal é @EnableAutoConfiguration
carregar todas as configurações obtidas antes e outras formas de configurações de contêiner IoC para o preparado ApplicationContext
.
10) Percorra e chame todos SpringApplicationRunListener
os métodos contextLoaded()
.
11) O método chamado ApplicationContext
para refresh()
concluir o último processo disponível para o contêiner IoC.
12) Descubra ApplicationContext
se existem registros no sistema atual CommandLineRunner
e, em caso afirmativo, percorra-os e execute-os.
13) Em circunstâncias normais, percorra o SpringApplicationRunListener
método de execução finished()
, (se ocorrer uma exceção em todo o processo, todos os métodos ainda serão chamados SpringApplicationRunListener
, finished()
mas neste caso, as informações da exceção serão passadas para processamento)
Depois de remover o ponto de notificação de eventos, todo o processo é o seguinte:
Este artigo usa a depuração de um programa de inicialização SpringBoot real como exemplo e analisa sua lógica de inicialização e princípios de configuração automática com referência ao diagrama de classe principal no processo.
Visão geral:
A imagem acima mostra o diagrama da estrutura de inicialização do SpringBoot. Descobrimos que o processo de inicialização é dividido principalmente em três partes:
-
A primeira parte é inicializar o módulo do SpringApplication e configurar algumas variáveis básicas de ambiente, recursos, construtores e ouvintes;
-
A segunda parte implementa o esquema de inicialização específico do aplicativo, incluindo o módulo de monitoramento do processo de inicialização, o módulo de ambiente de configuração de carregamento e o módulo de contexto de criação do núcleo;
-
A terceira parte é o módulo de configuração automática, que é o núcleo da configuração automática springboot e será discutido em detalhes na análise a seguir. Na rotina de inicialização abaixo iremos conectar as principais funções da estrutura.
comece:
Cada programa SpringBoot possui uma entrada principal, que é o método principal, que chama e inicia SpringApplication.run()
todo o programa spring-boot. A classe onde o método está localizado precisa usar @SpringBootApplication
anotações e @ImportResource
anotações (se necessário), @SpringBootApplication
incluindo três anotações. As funções são do seguinte modo:
-
@EnableAutoConfiguration
: O SpringBoot configura automaticamente o framework Spring com base nas dependências declaradas pelo aplicativo. -
@SpringBootConfiguration
(Interno@Configuration
): A classe marcada é igual a (applicationContext.xml
) no arquivo de configuração XML do spring, reunindo todas as transações de bean e fornecendo um contexto de spring. -
@ComponentScan
: Verificação de componente, que pode descobrir e montar beans automaticamente. Por padrão, os arquivos no caminho do pacote no método run do SpringApplication são verificadosBooter.class
, portanto, é melhor colocar a classe de inicialização no caminho do pacote raiz.
Classe de inicialização do SpringBoot
Primeiro digite o método run
No método run, uma instância SpringApplication é criada.Neste método de construção, podemos descobrir que ele chama um método initialize inicializado.
Isso serve principalmente para atribuir alguns valores iniciais ao objeto SpringApplication. Depois que o construtor é executado, voltamos ao método run
As seguintes etapas principais são implementadas neste método:
1. Crie um ouvinte de aplicativo SpringApplicationRunListeners
e comece a ouvir
2. Carregue o ambiente de configuração do SpringBoot ( ConfigurableEnvironment
), se ele for publicado através do contêiner da web, ele será carregado StandardEnvironment
e eventualmente será herdado ConfigurableEnvironment
. O diagrama de classes é o seguinte
Pode-se ver que *Environment finalmente implementa a interface PropertyResolver.Quando normalmente obtemos o método value correspondente à Key especificada no arquivo de configuração através do objeto de ambiente, chamamos o método getProperty da interface propertyResolver.
3. O ambiente de configuração ( Environment
) é adicionado ao objeto ouvinte ( SpringApplicationRunListeners
)
4. Crie o objeto de retorno do método run: ConfigurableApplicationContext
(contexto de configuração do aplicativo), podemos ver o método de criação:
O método primeiro obterá o contexto de aplicativo definido explicitamente ( applicationContextClass
), se ele não existir, então carregará a configuração do ambiente padrão (julgando se é web environment
), selecione AnnotationConfigApplicationContext
o contexto de anotação por padrão (carregue beans verificando todas as classes de anotação) e finalmente, instanciar através de BeanUtils o objeto de contexto e retorná-lo.
O diagrama de classe ConfigurableApplicationContext é o seguinte:
Depende principalmente das duas direções de sua herança:
-
LifeCycle: classe de ciclo de vida, que define start start, stop end, isRunning se deve executar o método de valor nulo do ciclo de vida médio
-
ApplicationContext: Classe de contexto do aplicativo, que herda principalmente beanFactory (classe de fábrica de bean)
5. De volta ao método run, o método prepareContext listeners、environment、applicationArguments、banner
associa outros componentes importantes ao objeto de contexto
6. O próximo refreshContext(context)
método (o método de inicialização é o seguinte) será spring-boot-starter-*
a chave para realizar a configuração automática (mybatis, redis, etc.), incluindo spring.factories
o trabalho principal de carregamento, instanciação de bean e assim por diante.
Após a configuração, o Springboot fez alguns trabalhos básicos de acabamento e retornou o contexto do ambiente de aplicação. Olhando para trás no processo geral, a inicialização do Springboot cria principalmente o ambiente de configuração (ambiente), ouvintes de eventos (ouvintes) e contexto do aplicativo (applicationContext) e, com base nas condições acima, começamos a instanciar os beans de que precisamos no contêiner .Até agora, através da inicialização do SpringBoot O programa foi construído.A seguir, vamos discutir como realizar a configuração automática.
Configuração automática:
No diagrama de estrutura de inicialização anterior, notamos que tanto a inicialização do aplicativo quanto o processo de execução específico invocavam o módulo de configuração automática do SpringBoot.
Módulo de configuração automática do SpringBoot
O principal uso deste módulo de configuração SpringFactoriesLoader
é o carregador de fábrica Spring. Este objeto fornece loadFactoryNames
métodos. Os parâmetros de entrada são factoryClass e classLoader, ou seja, o nome da classe de fábrica na figura acima e o carregador de classe correspondente precisam ser passados. O método será baseado no classLoader especificado, carregará o arquivo especificado no caminho de pesquisa do adicionador de classe, ou seja, spring.factories
o arquivo, a classe de fábrica de entrada é a interface e a classe correspondente no arquivo é a classe de implementação do interface, ou finalmente como a classe de implementação, então o arquivo geralmente é o seguinte Este tipo de coleção de nomes de classe um-para-muitos, depois de obter os nomes de classe dessas classes de implementação, o método retorna a coleção de nomes de classe e o chamador do loadFactoryNames
método obtém essas coleções e, em seguida, obtém os objetos de classe e os métodos de construção dessas classes por meio de reflexão e, finalmente, gera a instância.
Interface de fábrica e vários nomes de interface de classe de implementação
A figura abaixo nos ajuda a visualizar o processo de configuração automática.
Diagrama de relacionamento do componente-chave de configuração automática do SpringBoot
mybatis-spring-boot-starter
, spring-boot-starter-web
e os arquivos META-INF de outros componentes contêm spring.factories
arquivos. No módulo de configuração automática, SpringFactoriesLoader
o nome completo da classe no arquivo é coletado e uma matriz do nome completo da classe é retornada. O nome completo retornado da classe é instanciado por meio de reflexão, formando uma instância específica da fábrica, a instância da fábrica para gerar os beans que o componente precisa especificamente.
Mencionamos EnableAutoConfiguration
anotações antes, e seu diagrama de classes é o seguinte:
Pode-se descobrir que ele finalmente implementa ImportSelector
(seletor) e BeanClassLoaderAware
(middleware do carregador de classe do bean), focando nos seguintes AutoConfigurationImportSelector
métodos selectImports
.
[Falha na transferência da imagem do link externo, o site de origem pode ter um mecanismo de link anti-roubo, é recomendável salvar a imagem e carregá-la diretamente (img-Dm6tiUWw-1597051375071) (https://upload-images.jianshu.io/ upload_images/18688925-97932faefd1184cf?imageMogr2 /auto-orient/strip%7CimageView2/2/w/1240)]
Esse método é executado antes do processo de inicialização do springboot — instanciação do bean, e retorna uma lista de informações de classes a serem instanciadas. Sabemos que se as informações da classe forem obtidas, o spring pode carregar naturalmente a classe na jvm por meio do carregador de classes. o método select. Também pode ser obtido, não se preocupe, vamos continuar analisando abaixo.
O método neste método getCandidateConfigurations
, aprendido através da anotação do método, retorna uma lista de nomes de classe da classe de configuração automática, o método chama o loadFactoryNames
método, visualize o método
No código acima, você pode ver que o configurador automático encontrará a chave correspondente em factoryClass.getName()
todos spring.factories
os arquivos no caminho do sistema do projeto passado, para carregar as classes dentro. Vamos selecionar o arquivo mybatis-spring-boot-autoconfigure
sob estespring.factories
Entrando org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
, observe principalmente o cabeçalho da classe:
Descobriu que Spring @Configuration
é como um springBean marcado com anotações, continue a olhar para baixo,
-
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class})
: Quando essas duas classes existemSqlSessionFactory.class
, a classe de configuração será analisada, caso contrário, esta classe de configuração não será analisada, faz sentido, precisamos que mybatis retorne o objeto de sessão para nós e deve haver classes relacionadas à fábrica de sessão.SqlSessionFactoryBean.class
MybatisAutoConfiguration
-
@CondtionalOnBean(DataSource.class)
: Só lida com dataSources que foram declarados como beans. -
@ConditionalOnMissingBean(MapperFactoryBean.class)
Esta anotação significa que se o bean especificado pelo nome não existir no container, a injeção do bean será criada, caso contrário não será executada (o código fonte desta classe é longo, e o limite de espaço não foi totalmente colado)
A configuração acima pode garantir sqlSessionFactory、sqlSessionTemplate、dataSource
que os componentes exigidos pelo mybatis possam ser configurados automaticamente. @Configuration
A anotação forneceu o contexto do Spring, portanto, o método de configuração dos componentes acima tem o mesmo efeito que a configuração por meio do arquivo mybatis.xml quando o Spring é iniciado.
Através da análise, podemos constatar que, desde que exista um caminho de classe baseado no projeto SpringBoot e o dataSourceBean tenha sido registrado no contêiner, a configuração automática pode ser acionada, o que significa que precisamos apenas adicionar várias dependências exigidas pelo mybatis SqlSessionFactory.class
para SqlSessionFactoryBean.class
o projeto maven A configuração automática pode ser acionada, mas se a dependência nativa do mybatis for introduzida, a classe de configuração automática deve ser modificada para cada função integrada, para que o efeito pronto para uso não seja obtido.
Portanto, o Spring-boot nos fornece um iniciador unificado que pode configurar diretamente as classes relacionadas, e as dependências (mybatis) necessárias para acionar a configuração automática são as seguintes:
Aqui estão mybatis-spring-boot-starter
todas as dependências no arquivo pom.xml no código-fonte interceptado:
Devido à natureza transitiva das dependências maven, podemos contar com todas as classes que precisam ser configuradas automaticamente, desde que contemos com o iniciador para obter funções prontas para uso. Também mostra que o Springboot simplifica a grande quantidade de configuração XML e o complexo gerenciamento de dependências trazido pelo framework Spring, permitindo que os desenvolvedores prestem mais atenção ao desenvolvimento da lógica de negócios.
afinal
Preste atenção na conta oficial: Programmer Chasing the Wind. Responder 003 Obtenha o manual de perguntas da entrevista Java 2020 mais recente (mais de 200 páginas de documentos PDF)