Рассказываем о принципе автоматической сборки SpringBoot

Spring Boot Spring

Эта статья была включена в Java-проект JavaGuide Github 95k+ Star. Адрес проекта JavaGuide:GitHub.com/snail Climb/….

автор:Miki-byte-1024 & Snailclimb

Каждый раз, когда задают вопрос о Spring Boot, интервьюер любит задавать этот вопрос: «Расскажите мне о принципе автопроводки Spring Boot?».

Я думаю, что мы можем ответить следующим образом:

  1. Что такое автопроводка SpringBoot?
  2. Как SpringBoot реализует автопроводку? Как добиться загрузки по требованию?
  3. Как внедрить Стартер?

Из-за недостатка места эта статья не является подробной, и друзья также могут напрямую использовать метод отладки, чтобы увидеть исходный код части автоматической сборки SpringBoot.

предисловие

Друзья, которые использовали Spring, должны бояться, что ими будут управлять XML-конфигурации. Даже если Spring позже представит конфигурацию на основе аннотаций, нам все равно придется использовать XML или Java для явной настройки, когда мы включим некоторые функции Spring или введем сторонние зависимости.

Например. Когда нет Spring Boot, мы пишем веб-сервис RestFul, и нам нужно сначала настроить следующее.

@Configuration
public class RESTConfiguration
{
    @Bean
    public View jsonTemplate() {
        MappingJackson2JsonView view = new MappingJackson2JsonView();
        view.setPrettyPrint(true);
        return view;
    }

    @Bean
    public ViewResolver viewResolver() {
        return new BeanNameViewResolver();
    }
}

spring-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context/ http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc/ http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.howtodoinjava.demo" />
    <mvc:annotation-driven />

    <!-- JSON Support -->
    <bean name="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
    <bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>

</beans>

Однако для проекта Spring Boot нам нужно только добавить соответствующие зависимости без настройки, запустив следующиеmainметод.

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

И мы передаем глобальный файл конфигурации Spring Bootapplication.propertiesилиapplication.ymlВы можете настроить проект, например изменить номер порта, настроить свойства JPA и т. д.

Почему Spring Boot так кисло использовать?Это благодаря автоматической сборке.Можно сказать, что автопроводка является ядром Spring Boot, так что же такое автопроводка?

Что такое автопроводка SpringBoot?

Когда мы сейчас говорим об автомонтировании, обычно это ассоциируется со Spring Boot. Однако на самом деле Spring Framework уже реализовал эту функцию. Spring Boot только дополнительно оптимизирует его через SPI.

SpringBoot определяет набор спецификаций интерфейса, которые предусматривают, что: SpringBoot будет сканировать внешний эталонный jar-пакет при запуске.META-INF/spring.factoriesфайла, загрузите информацию о типе, настроенную в файле, в контейнер Spring (это включает в себя механизм загрузки класса JVM и знания контейнера Spring) и выполните различные операции, определенные в классе. Для внешних jar-файлов вам нужно только следовать стандартам, определенным SpringBoot, для установки собственных функций в SpringBoot.

Без Spring Boot, если нам нужно ввести сторонние зависимости, требуется ручная настройка, что очень хлопотно. Однако в Spring Boot мы можем напрямую ввести стартер. Например, если вы хотите использовать Redis в своем проекте, вы можете напрямую внедрить соответствующий стартер в проект.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

После введения стартера мы можем использовать функции, предоставляемые сторонними компонентами, с несколькими аннотациями и некоторой простой настройкой.

На мой взгляд, автовайринг можно просто понимать как:Определенную функцию можно реализовать с помощью Spring Boot через аннотации или какую-то простую настройку.

Как SpringBoot реализует автопроводку?

Давайте сначала посмотрим на основные аннотации SpringBoot.SpringBootApplication.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
<1.>@SpringBootConfiguration
<2.>@ComponentScan
<3.>@EnableAutoConfiguration
public @interface SpringBootApplication {

}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration //实际上它也是一个配置类
public @interface SpringBootConfiguration {
}

наверное можно@SpringBootApplicationрассматривается как@Configuration,@EnableAutoConfiguration,@ComponentScanСборник аннотаций. Согласно официальному сайту SpringBoot, эти три аннотации выполняют следующие функции:

  • @EnableAutoConfiguration: включить механизм автоматической настройки SpringBoot.

  • @Configuration: позволяет зарегистрировать дополнительные компоненты в контексте или импортировать другие классы конфигурации

  • @ComponentScan: сканирование есть@Component (@Service,@Controller) аннотированный bean-компонент, аннотация будет сканировать все классы в пакете, где класс запуска находится по умолчанию, и вы можете настроить, чтобы не сканировать некоторые bean-компоненты. Как показано на изображении ниже, контейнер будет исключатьTypeExcludeFilterиAutoConfigurationExcludeFilter.

@EnableAutoConfigurationЭто важная аннотация для реализации автоматической сборки, мы начнем с этой аннотации.

@EnableAutoConfiguration: основная аннотация для реализации автоматической сборки.

EnableAutoConfigurationПростая аннотация, реализация основной функции автопроводки на самом деле выполняетсяAutoConfigurationImportSelectorсвоего рода.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所欲组件注册到容器中
@Import({AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

Теперь сосредоточимся на анализеAutoConfigurationImportSelectorЧто именно делает класс?

AutoConfigurationImportSelector: загружает автоматически связанные классы.

AutoConfigurationImportSelectorСистема наследования классов выглядит следующим образом:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

}

public interface DeferredImportSelector extends ImportSelector {

}

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata var1);
}

Как можно видеть,AutoConfigurationImportSelectorкласс реализуетImportSelectorинтерфейс, реализующийselectImportsметод, который в основном используется дляПолучите полные имена классов всех подходящих классов, которые необходимо загрузить в контейнер IoC..

private static final String[] NO_IMPORTS = new String[0];

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // <1>.判断自动装配开关是否打开
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
          //<2>.获取所有需要装配的bean
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

Здесь мы должны сосредоточиться наgetAutoConfigurationEntry()метод, этот метод в основном отвечает за загрузку класса автоматической конфигурации.

Цепочка вызовов методов выглядит следующим образом:

Теперь мы объединяемgetAutoConfigurationEntry()Исходный код для детального анализа:

private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();

AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
        //<1>.
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            //<2>.
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //<3>.
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //<4>.
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

шаг 1:

Определите, включен ли переключатель автосборки. дефолтspring.boot.enableautoconfiguration=true, доступны наapplication.propertiesилиapplication.ymlустановить в

Шаг 2:

для полученияEnableAutoConfigurationв примечанияхexcludeиexcludeName.

Шаг 3

Получите все классы конфигурации, которые должны быть автоматически подключены, прочитайтеMETA-INF/spring.factories

spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

Как видно из рисунка ниже, конфигурационное содержимое этого файла было нами прочитано.XXXAutoConfigurationРоль заключается в загрузке компонентов по запросу.

Это зависит не толькоMETA-INF/spring.factoriesЧитается, что все Spring Boot Starter подMETA-INF/spring.factoriesбудет прочитан.

Итак, вы можете ясно видеть, что создается Spring Boot Starter пула соединений с базой данных druid.META-INF/spring.factoriesдокумент.

Если мы хотим сами создать Spring Boot Starter, этот шаг необходим.

Шаг 4:

В этот момент интервьюер может спросить вас:spring.factoriesС таким количеством конфигураций вам нужно загружать их все каждый раз при запуске? ".

Очевидно, что это не реально. Мы отлаживаем обратно, и вы найдете,configurationsзначение уменьшилось.

Поскольку этот шаг прошел проверку,@ConditionalOnXXXВсе условия выполнены, класс вступит в силу.

@Configuration
// 检查相关的类:RabbitTemplate 和 Channel是否存在
// 存在才会加载
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}

Заинтересованные детской обувью могут узнать больше об условных аннотациях, предоставляемых Spring Boot.

  • @ConditionalOnBean: Когда в контейнере есть указанный компонент
  • @ConditionalOnMissingBean: Когда в контейнере не указан компонент
  • @ConditionalOnSingleCandidate: когда указанный компонент имеет только один в контейнере или хотя их несколько, но укажите предпочтительный компонент
  • @ConditionalOnClass: когда в пути к классам есть указанный класс
  • @ConditionalOnMissingClass: когда в пути к классам не указан класс
  • @ConditionalOnProperty: Имеет ли указанное свойство указанное значение.
  • @ConditionalOnResource: Есть ли указанное значение классов
  • @ConditionalOnExpression: На основе выражений SpEL в качестве условий суждения
  • @ConditionalOnJava: на основе версии Java в качестве условия суждения
  • @ConditionalOnJndi: разница в указанной позиции при наличии JNDI
  • @ConditionalOnNotWebApplication: при условии, что текущий проект не является веб-проектом
  • @ConditionalOnWebApplication: при условии, что текущий проект является веб-проектом.

Как реализовать Стартер

Если вы не просто говорите о поддельном дескрипторе, давайте сейчас воспользуемся стартером для реализации пользовательского пула потоков.

Первым шагом является созданиеthreadpool-spring-boot-starterпроект

Второй шаг — представить зависимости, связанные с Spring Boot.

Третий шаг, создайтеThreadPoolAutoConfiguration

Четвертый шаг, вthreadpool-spring-boot-starterСоздан под пакет ресурсов проектаMETA-INF/spring.factoriesдокумент

Представлен последний новый проектthreadpool-spring-boot-starter

Тест пройден! ! !

Суммировать

Весенняя загрузка через@EnableAutoConfigurationВключите автопроводку и, наконец, загрузите через SpringFactoriesLoader.META-INF/spring.factoriesКласс автоконфигурации в реализует автосборку, а класс автоконфигурации фактически через@ConditionalКласс конфигурации, загружаемый по требованию, должен быть введен, чтобы он вступил в силу.spring-boot-starter-xxxЗависимости запуска реализации пакета

конец статьи

Я Brother Guide, бэкенд-разработчик Java, немного фронтенда, свободный подросток. Увидимся в следующий раз! Поиск в WeChat“JavaGuide"Ответить"интервью сюрприз” Возьмите 4 оригинальных PDF-файла, которые я собрал