весенняя загрузка

Spring Boot

весенняя загрузка

Многие функции Spring Boot реализованы на основе Spring Framework, например, хорошо известные функции, которые также являются его основными функциями:Автопроводка компонентов. Он может автоматически настраивать приложения Spring Boot в соответствии с зависимыми пакетами jar, например: если класс DispatcherServlet существует в пути к классам, bean-компоненты, связанные с springMvc, будут настроены автоматически.

И все, что вам нужно, это написать класс запуска, плюс@SpringBootApplicationАннотируйте, выполните его основной метод, а затем передайте его Sping Boot:

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

Почему многие фичи Spring Boot реализованы на базе Spring framework Прежде чем входить в тему, нужно разобраться в аннотациях паттернов

аннотация схемы

Аннотации схемы Spring:

Аннотация, используемая для объявления роли «компонента» в приложении, то есть аннотированная этой аннотацией, указывающая, что класс и т. д. играет роль компонента в приложении. Например@RepositoryАннотация к классу, указывающая, что этот класс играет роль хранилища.

а также@Componentиспользуется как общий компонент схемы, любой@ComponentВсе аннотированные компоненты являются кандидатами на сканирование компонентов. Точно так же любой@ComponentАннотированные аннотации, такие как@Service, когда какой-либо компонент аннотирует его, также считается кандидатом на сканирование компонентов.

Аннотации Spring Framework описание сцены начальная версия
@Repository хранилище данных 2.0
@Component Общие компоненты 2.5
@Service Служить 2.5
@Controller контроллер 2.5
@Configuration класс конфигурации 3.0

Метод сборки

До весны 2.5 конфигурация xml использовалась для реализации:

<context:component-scan base-package="com.wxpay.*"/>

После весны 3.1 вы можете использовать аннотации для достижения:

@ComponentScan("com.wxpay.*")

Аннотации пользовательской схемы

Два свойства аннотаций схемы:

  1. Производная:@component,@RepositoryАннотации имеют сигнатуры значений, которые сохраняют согласованность сигнатур.Это производное от аннотаций.Другими словами, это@componentДоступны аннотированные аннотации@componentфункция
  2. Иерархический: объявление аннотаций второго уровняSecondLevelRepository,нашSecondLevelRepositoryполученный изFirstLevelRepository, это иерархия

Строго говоря, аннотации не являются производными и иерархическими, причина этого в том, чтобы облегчить понимание, потому что многие аннотации в Spring являются производными и иерархическими структурами.

Возможно, предыдущее утверждение недостаточно ясно, и каждый может услышать его в облаке.Далее, давайте используем пример, чтобы проиллюстрировать характеристики аннотаций режима.

Во-первых, давайте определим аннотацию, используя@RepositoryВызывать:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repository
public @interface FirstLevelRepository {
    String value() default "";
}

Затем определите класс, аннотированный приведенной выше аннотацией:

@FirstLevelRepository(value = "myFirstLevelRepository")
public class MyFirstLevelRepository {

}

Наконец, определите класс начальной загрузки, который используется здесь.@ComponentScanОтсканируйте вышеуказанный класс:

@ComponentScan("com.lingxiao.springboot.Repository")
public class RepositoryBootstrap {
    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext =
                new SpringApplicationBuilder(RepositoryBootstrap.class).web(WebApplicationType.NONE).run(args);
        MyFirstLevelRepository firstLevelRepository = applicationContext
                .getBean("myFirstLevelRepository", MyFirstLevelRepository.class);
        System.out.println("获取到的bean" + firstLevelRepository);
        applicationContext.close();
    }
}

Наконец-то получилось успешноMyFirstLevelRepository, здесь видно, что@RepositoryАннотированные аннотации@FirstLevelRepository, как отношения наследования, должны иметь@Repositoryфункция.

Затем мы определяем другую аннотацию, используя@FirstLevelRepositoryобозначить это:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@FirstLevelRepository
public @interface SeondLevelRepository {
    String value() default "";
}

Таким же образом используйте эту аннотацию для аннотации вышеприведенного класса.MyFirstLevelRepository, запустите класс BootstrapRepositoryBootstrap, также можно успешно получить боб. Это также подтверждает, что аннотация шаблонаПроизводнаяа такжеИерархический.

@SpringBootApplication также является модальной аннотацией.

Что ж, приведенный выше пример объяснил характеристики аннотации шаблона, мы можем рассмотреть его далее.@SpringBootApplicationЭто аннотировано, зайдите и посмотрите исходный код:

Исходная версия — spring-boot-2.2.5.RELEASE.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
@SpringBootConfiguration
@EnableAutoConfiguration
public @interface SpringBootApplication {
}

можно увидеть@SpringBootApplicationсоставная аннотация

@ComponentScan, настроить автоматическое сканирование пакетов, нечего сказать

нажмите еще раз@SpringBootConfiguration, мы можем видеть:

@Configuration
public @interface SpringBootConfiguration {
    
}

@SpringBootConfigurationодеяло@Configuration, проиллюстрировать@SpringBootConfigurationи отмечено им@SpringBootApplicationявляется аннотацией схемы

После@EnableAutoConfiguration, что дальше@Enable模块装配, который также является ядром автоматической сборки

@Включить сборку модуля

Используя сборку модуля @Enable, можно настроить, какие модули будут активированы.

Реализация фреймворка Модуль аннотаций
Spring Framework @EnableWebMvc
@EnableTransationManagement
@EnableCaching Кэширующий модуль
@EnableMBeanExport JMX-модуль
@EnableAsync Модуль асинхронной обработки
@EnableWebFlux Модуль веб-потока
Spring Boot @EnableAutoConfiguration Модули автоматической сборки
@EnableOAuth2Sao Модуль единого входа OAuth2

Есть два способа реализовать @Enable

Реализация на основе аннотаций

Сначала определите Bean:

@Configuration
public class HelloWorldConfiguration {
 
    @Bean
    public String helloWorld() { // 方法名即 Bean 名称
        return "Hello,World";
    }
}

Затем определите другую аннотацию, используйте@ImportИмпортируйте только что определенный компонент:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}

После выполнения двух вышеуказанных шагов нам нужно только использовать@EnableHelloWorldПри аннотации класса компонент загружается в контейнер Spring.

@EnableHelloWorld
public class EnableHelloWorldBootstrap {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);
        // helloWorld Bean 是否存在
        String helloWorld =
                context.getBean("helloWorld", String.class);
        System.out.println("获取到的bean: " + hello);
        // 关闭上下文
        context.close();
    }
}

Запустите, чтобы увидеть эффект:

Вы можете видеть, что компонент действительно загружен в контейнер Spring.

На основе реализации, управляемой интерфейсом

выполнитьImportSelectorинтерфейс, который его реализуетselectImportsметод, который возвращает массив строкового типа и имя класса, хранящееся в массиве:

public class HelloWorldImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{HelloWorldConfiguration.class.getName()};
    }
}

Затем измените аннотацию, определенную выше:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
//@Import({HelloWorldConfiguration.class})  enable注解驱动的方式
@Import({HelloWorldImportSelector.class})  //接口编程的方式
public @interface EnableHelloWorld {

}

Видно, что реализация на основе интерфейса более гибкая, мы можемselectImportsСделайте некоторые суждения, при необходимости верните разные массивы имен классов, а затем соберите их в соответствии с именами классов.

Ядро автопроводки Spring Boot

давайте оглянемся назад@EnableAutoConfigurationЭта аннотация:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
}

нажмите еще раз@AutoConfigurationPackageпосмотри

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

использовать@ImportЧтобы импортировать компонент в контейнер Spring, используйте Registrar.class.

Запустите проект springboot, отладьте, чтобы увидеть, вы можете обнаружить, что метаданные@SpringBootApplicationАннотированный класс, посмотрите еще разnew PackageImport(metadata).getPackageName()Значение:

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

Тогда мы увидимEnableAutoConfigurationтакже используется@import, импортированный AutoConfigurationImportSelector.class, мы можем знать из имени этого класса, что он указан для реализацииImportSelectorИнтерфейс, переопределяющий метод selectImports, поэтому мы смотрим непосредственно на selectImports:

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
	if (!isEnabled(annotationMetadata)) {
		return NO_IMPORTS;
	}
	AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
	AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata);
		return tringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

Вы можете видеть, что возвращаемый результат проходит черезautoConfigurationEntryизgetConfigurations()получено, поэтому мы смотрим непосредственно наgetAutoConfigurationEntryметод:

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

Точно так же здесь мы вводимgetCandidateConfigurationsПосмотрите на метод:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
}

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

Условная сборка

Существует два типа аннотаций условной сборки:

Весенние аннотации описание сцены начальная версия
@Profile Настраиваемая условная сборка 3.1
@Conditional Программирование условной сборки 4.0

После 4.0 @profile также стал @Conditional для достижения

Сценарий приложения: обычно используется для переключения между производственной средой и средой разработки, то есть для добавления аннотаций к классам или методам и установки идентификаторов среды, таких какjava7,java8, мы покажем, как использовать простое многоцелое суммирование

@Profile реализует условную сборку

Сначала определите интерфейс:

public interface CalCulateService {
    /**
     * 整数求和
     * @param args
     * @return
     */
    Integer sum(Integer... args);
}

Затем реализуйте метод суммирования для JDK7 и JDK8 соответственно.

Первый — это реализация JDK7:

/**
 * java7的方式实现求和
 */
@Profile("Java7")
@Service
public class Java7CalCulateServiceImpl implements CalCulateService {
    @Override
    public Integer sum(Integer... args) {
        System.out.println("java7的方式求和");
        int sum = 0;
        for (int i = 0; i < args.length; i++) {
            sum+=args[i];
        }
        return sum;
    }
}

Затем идет реализация JDK8:

@Profile("Java8")
@Service
public class Java8CalCulateServiceImpl implements CalCulateService {
    @Override
    public Integer sum(Integer... args) {
        System.out.println("java8的方式求和");
        int sum = Stream.of(args).reduce(0,Integer::sum);
        return sum;
    }
}

Затем создайте класс запуска, при запуске контейнера используйте.profiles("Java8")чтобы указать, какую версию использовать для расчета:

@SpringBootApplication(scanBasePackages = "com.lingxiao.springboot.service")
public class CalCulateServiceBootstrap {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext =
                new SpringApplicationBuilder(CalCulateServiceBootstrap.class)
                        .web(WebApplicationType.NONE)
                        .profiles("Java8")
                        .run(args);
        CalCulateService calCulateService = applicationContext
                .getBean(CalCulateService.class);
        System.out.println("求和: " + calCulateService.sum(1,2,3,4,5));
        applicationContext.close();
    }
}

результат операции:

Вы можете видеть, что это действительно суммирование, реализованное способом java8.

@Conditional реализует условную сборку

При создании бина добавляется ряд условий, только при выполнении всех указанных условий компонент может быть зарегистрирован. В использовании@ConditionalКогда класс условного суждения должен реализоватьConditionинтерфейс

Теперь настраиваем условную сборку и создаем аннотацию:

/**
 * 编程方式实现条件装配
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {
    /**
     * java系统属性名称
     * @return
     */
    String name();

    /**
     * java系统属性值
     */
    String value();
}

В этой аннотации определены два свойстваnameа такжеvalue, эти два свойства используются при реализации условного сужденияOnSystemPropertyConditionбудет использоваться в.

Создайте класс условного суждения:

/**
 * 编程方式实现条件装配
 */
public class OnSystemPropertyCondition implements Condition {

    /**
     *
     * @param context
     * @param metadata 源信息
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
        List<Object> nameObj = attributes.get("name");
        String name = "";
        if (!CollectionUtils.isEmpty(nameObj)) {
            name = String.valueOf(attributes.get("name").get(0));
        }
        String value = "";
        if (!CollectionUtils.isEmpty(nameObj)) {
            value = String.valueOf(attributes.get("value").get(0));
        }
        String property = System.getProperty(name);
        return value.equals(property);  //条件满足才会返回装配
    }
}

использоватьmetadata.getAllAnnotationAttributesПолучите значение атрибута в аннотации, а затем оцените, выполняется ли условие, и сборка не будет выполняться, пока условие не будет выполнено.

Создайте класс начальной загрузки:

public class ConditionalOnSystemPropertyBootstrap {

    @Bean
    @ConditionalOnSystemProperty(name = "java.vm.specification.version",value = "1.8")
    public String helloWorld(){
        return "hello world";
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(ConditionalOnSystemPropertyBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);
        String helloWorld = context.getBean("helloWorld", String.class);
        System.out.println("bean name:  "+helloWorld);
        context.close();
    }
}

В этом классе начальной загрузки мы объявляем bean-компонент helloWorld и добавляем к этому методу аннотацию условной сборки, гдеjava.vm.specification.versionЯвляется ли полученная версия виртуальной машины Java, если виртуальная машина 1.8, bean-компонент будет загружен в контейнер Spring

Когда текущая версия 1.8, запустите код:

С нормальной загрузкой проблем нет, когда переключаем версии, снова запускаем:

Было обнаружено, что было сообщено об ошибке, и Spring не смог найти бин, что означает, что бин не соответствует условиям для загрузки.

Реализовать автоматическую сборку

Рори так много сказал, давайте посмотрим, как реализовать автопроводку Spring Boot.

Автоматическая сборка Spring Boot сочетает в себе вышеупомянутые технологии, поэтому мы можем реализовать автоматическую сборку на основе знаний Spring Framework.Этапы следующие:

  • Реализовать класс, который необходимо собрать
  • Весенняя загрузка фабрики, настройте классы, которые необходимо собрать
    • Класс реализации: SpringFactoryLoader
    • Ресурсы конфигурации: META-INF/spring.factories
  • Активировать автопроводку — @EnableAutoConfiguration

Сначала создайте класс:

/**
 * 自动装配
 */
@Configuration   //模式注解
@EnableHelloWorld  //Enable模块装配
@ConditionalOnSystemProperty(name = "java.vm.specification.version",value = "1.8") //条件装配
public class HelloWorldAutoConfiguration {

}

Как видите, все три модифицированные аннотации основаны на Spring Framework.Теперь нам нужно только настроить файл spring.factories.Мы создаем новый файл в каталоге ресурсов:

Содержимое находится в формате ключ-значение, а ключ@EnableAutoConfiguration, value — это путь к пакету класса autowired:

# 自动装配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.lingxiao.springboot.configuration.HelloWorldAutoConfiguration

Затем создайте еще один класс запуска:

@EnableAutoConfiguration
public class EnableAutoConfigurationBootstrap {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableAutoConfigurationBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);
        String hello = context
                .getBean("helloWorld", String.class);
        System.out.println("获取到的bean: " + hello);
        context.close();
    }
}

Результатом операции является правильное получение боба. Вот краткое изложение всего процесса:

  1. использовать@EnableAutoConfigurationАктивируйте автопроводку, и Spring Boot пойдетspring.factoriesРазберите классы, которые должны быть автоматически подключены в файлеHelloWorldAutoConfiguration
  2. сборкаHelloWorldAutoConfigurationКогда пришло время судить, соответствует ли она требованиям сборки, вот среда jdk1.8, значит, она соответствует требованиям.
  3. HelloWorldAutoConfigurationнаходится@EnableHelloWorldотмеченный,@EnableHelloWorldпройти через@Import({HelloWorldImportSelector.class})способ введенияHelloWorldImportSelector
  4. существуетHelloWorldImportSelectorизselectImportsметод возвращенHelloWorldConfigurationимя класса
  5. существуетHelloWorldConfigurationзагрузкаhelloWorld

Исходный код загружен на gitee:Нажмите, чтобы посетить

Ссылаться на:

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

МООК: основная технология Spring Boot 2.0 Deep Practice