Se você não entende o princípio da inicialização do Spring Boot, você deve dar uma olhada!

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( @SpringBootConfigurationClique 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 @Configurationnã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, @Configurationela é, 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 @Configurationdefiniçã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 @Beanmé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, @Configurationvocê 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(); 
    } 
}

@ConfigurationA classe anotada identifica que esta classe pode usar o contêiner Spring IoC como uma fonte de definições de bean.

@BeanA 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

@ComponentScanEsta anotação é muito importante no Spring. Corresponde aos elementos na configuração XML. @ComponentScanSua função é verificar e carregar automaticamente componentes qualificados (como @Componente @Repositoryetc.) 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á @ComponentScana 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 @EnableAutoConfigurationesta Annotation é a mais importante, por isso vou interpretá-la no final.Você ainda se lembra da @Enabledefinição de Annotation com vários nomes fornecidos pelo framework Spring? Por @EnableScheduling、@EnableCaching、@EnableMBeanExportexemplo, @EnableAutoConfigurationo conceito e a maneira de fazer as coisas estão na mesma linha.Um breve resumo é que, com a ajuda @Importdo 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 @EnableAutoConfigurationcom 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!

@EnableAutoConfigurationO 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,@EnableAutoConfigurationpode ajudar o aplicativo SpringBoot a carregar todas as @Configurationconfigurações elegíveis na criação e uso atuais do SpringBoot. SpringFactoriesLoaderAssim como um "polvo", com o suporte de uma classe de ferramenta original do framework Spring: a @EnableAutoConfigurationfunçã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 @EnableAutoConfigurationnome completo da classe org.springframework.boot.autoconfigure.EnableAutoConfigurationcomo chave de pesquisa, um conjunto correspondente de @Configurationclasses pode ser obtido.

imagem

A imagem acima é META-INF/spring.factoriesum trecho do arquivo de configuração no pacote de dependência autoconfigure do SpringBoot, que pode ilustrar bem o problema.

Portanto, @EnableAutoConfigurationo cavaleiro mágico da configuração automática torna-se: pesquisar todos os META-INF/spring.factoriesarquivos de configuração do caminho de classe e org.springframework.boot.autoconfigure.EnableutoConfigurationinstanciar os itens de configuração correspondentes na @Configurationclasse 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 SpringFactoriesLoaderlocaliza e carrega todos os disponíveis no classpath do aplicativo ApplicationContextInitializer.

  • Use SpringFactoriesLoaderlocaliza e carrega todos os disponíveis no classpath do aplicativo ApplicationListener.

  • 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 SpringFactoriesLoadercarregados 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 SpringApplicationRunListeneros 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 applicationContextClasso tipo e o resultado da inferência da fase de inicialização, decida qual tipo criar para o aplicativo SpringBoot atual ApplicationContexte 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-FactoriesLoaderpara encontrar e carregar todos os disponíveis no classpath ApplicationContext-Initializere, em seguida, percorrer e chamar esses métodos ApplicationContextInitializer( applicationContext) para processar posteriormente initializeos criados .ApplicationContext

8) Atravesse e chame todos SpringApplicationRunListeneros métodos contextPrepared().

9) A etapa principal é @EnableAutoConfigurationcarregar 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 SpringApplicationRunListeneros métodos contextLoaded().

11) O método chamado ApplicationContextpara refresh()concluir o último processo disponível para o contêiner IoC.

12) Descubra ApplicationContextse existem registros no sistema atual CommandLineRunnere, em caso afirmativo, percorra-os e execute-os.

13) Em circunstâncias normais, percorra o SpringApplicationRunListenermé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 @SpringBootApplicationanotações e @ImportResourceanotações (se necessário), @SpringBootApplicationincluindo 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 verificados Booter.class, portanto, é melhor colocar a classe de inicialização no caminho do pacote raiz.

imagem

Classe de inicialização do SpringBoot

Primeiro digite o método run

imagem.gif

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 SpringApplicationRunListenerse 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 StandardEnvironmente eventualmente será herdado ConfigurableEnvironment. O diagrama de classes é o seguinte

imagem

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 AnnotationConfigApplicationContexto 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、bannerassocia 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.factorieso 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 loadFactoryNamesmé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.factorieso 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 loadFactoryNamesmé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-webe os arquivos META-INF de outros componentes contêm spring.factoriesarquivos. No módulo de configuração automática, SpringFactoriesLoadero 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 EnableAutoConfigurationanotaçõ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 AutoConfigurationImportSelectormé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 loadFactoryNamesmétodo, visualize o método

imagem.gif

No código acima, você pode ver que o configurador automático encontrará a chave correspondente em factoryClass.getName()todos spring.factoriesos arquivos no caminho do sistema do projeto passado, para carregar as classes dentro. Vamos selecionar o arquivo mybatis-spring-boot-autoconfiguresob estespring.factories

imagem.gif

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 existem SqlSessionFactory.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.classMybatisAutoConfiguration

  • @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、dataSourceque os componentes exigidos pelo mybatis possam ser configurados automaticamente. @ConfigurationA 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.classpara SqlSessionFactoryBean.classo 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-startertodas 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)

Acho que você gosta

Origin blog.csdn.net/Design407/article/details/107917917
Recomendado
Clasificación