Добавить Автора
Введение
Студенты, которые использовали springboot, должны уже знать, что springboot значительно упрощает начальный процесс построения и разработки проекта, настраивая использование многих фреймворков по умолчанию.
Цель этой статьи — шаг за шагом проанализировать процесс запуска Springboot, на этот раз в основном для анализа автоматической сборки функций Springboot.
Итак, сначала давайте посмотрим, как наши веб-проекты были созданы в прошлом.Обычно нам нужно создать веб-приложение на основе Spring.Нам нужно сделать следующее:
- Связанные пакеты jar вводятся в файл pom, включая spring, springmvc, redis, mybaits, log4j, mysql-connector-java и другие связанные файлы jar…
- Настройте web.xml, конфигурацию прослушивателя, конфигурацию фильтра, конфигурацию сервлета, конфигурацию log4j, конфигурацию ошибок…
- Настройте соединение с базой данных, настройте весеннюю транзакцию
- Настройка преобразователей представлений
- Включить аннотацию и автоматическое сканирование
- После завершения настройки разверните tomcat и начните отладку. ...
На сборку начального проекта может уйти час или полдня на его сохранение, но все будет очень удобно после использования SpringBoot.Давайте сначала разберем зависимости запуска и автоматическую настройку SpringBoot.
2. Стартовая зависимость
1. Добавьте в наш pom-файл следующие jar-файлы:
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis 开发包 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--springboot web模块支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- Пакет spring-boot-starter-web автоматически помогает нам ввести соответствующие пакеты jar, необходимые для разработки веб-модуля.
- mybatis-spring-boot-starter помог нам представить пакеты jar, связанные с разработкой dao.
- spring-boot-starter-xxx — это официальный стартер, а xxx-spring-boot-starter — сторонний стартер.
Сделайте скриншот нашего mybatis-spring-boot-starter
Видно, что у mybatis-spring-boot-starter нет никакого исходного кода, только pom-файл, его роль — помочь нам представить другие jar-файлы.
2. Настройте источник данных
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://127.0.0.1:3306/mybatis_test
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
hikari:
# 最小空闲连接数量
minimum-idle: 5
# 连接池最大连接数,默认是10
maximum-pool-size: 60
# 此属性控制从池返回的连接的默认自动提交行为,默认值:true
auto-commit: true
# 一个连接idle状态的最大时长(毫秒),超时则被释放(retired),缺省:10分钟
idle-timeout: 600000
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
max-lifetime: 1800000
# 数据库连接超时时间,默认30秒,即30000
connection-timeout: 60000
stater, который поможет нам завершить соответствующий пакет jar, необходимый для запуска проекта. Эта проблема снова, традиционная конфигурация приложения spring application.xml не должна выполняться во многих bean-компонентах, таких как конфигурация dataSource, конфигурация transactionManager... как springboot поможет нам выполнить эту конфигурацию bean-компонентов?
Давайте проанализируем этот процесс
3. Автоматическая настройка
1. Конфигурация бина на основе java-кода
Взяв в качестве примера mybatis, на приведенном выше снимке экрана мы обнаружили, что пакет mybatis-spring-boot-starter помог нам ввести пакет mybatis-spring-boot-autoconfigure, как показано ниже:
В нем есть класс MybatisAutoConfiguration, откройте этот класс, чтобы посмотреть, что там.
Учащиеся, знакомые с двумя bean-компонентами @Configuration& и @Bean, возможно, уже знакомы с ними. Эти две аннотации можно использовать вместе для создания класса конфигурации на основе кода Java, который можно использовать для замены соответствующего файла конфигурации xml.
Классы, аннотированные с @Configuration, могут рассматриваться как фабрики, которые создают фасонные экземпляры для контейнера для весной IOC для управления.
Аннотация @Bean говорит о весне, что метод, аннотированный с @Bean, вернет объект, который должен быть зарегистрирован с весенним контейнером.
Таким образом, приведенный выше класс MybatisAutoConfiguration автоматически помогает нам генерировать важные экземпляры Mybatis, такие как SqlSessionFactory, и передавать их контейнеру Spring для управления, тем самым завершая автоматическую регистрацию bean-компонентов.
2. Автоматически настраивать условные зависимости
Из аннотаций, используемых в классе MybatisAutoConfiguration, видно, что существуют зависимости для завершения автоматической настройки.
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {
private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
private final MybatisProperties properties;
private final Interceptor[] interceptors;
private final ResourceLoader resourceLoader;
private final DatabaseIdProvider databaseIdProvider;
private final List<ConfigurationCustomizer> configurationCustomizers;
......
Первый предварительный просмотр Springboot — это общие аннотации условной зависимости:
- @ConditionalOnBean, экземпляр bean-компонента будет создан только в том случае, если в текущем контексте есть bean-компонент.
- @ConditionalOnClass, когда класс находится в пути к классам, будет создан экземпляр компонента.
- @ConditionalOnExpression, когда выражение истинно, будет создан экземпляр компонента.
- @ConditionalOnMissingBean экземпляр bean-компонента будет создан только в том случае, если он не существует в текущем контексте.
- @ConditionalOnMissingClass, когда класс не существует в пути к классам, будет создан экземпляр компонента.
- @ConditionalOnNotWebApplication, экземпляр этого компонента создается, если он не является веб-приложением.
- @AutoConfigureAfter, создайте экземпляр компонента после его автоматической настройки.
- @AutoConfigureBefore, создайте экземпляр компонента до его автоматической настройки.
Следовательно, для завершения автоматической настройки MyBatis, двух классов, SQLSessionFactory.Class и SQLSessionFactoryBean.Class, необходимо существовать в классовой патке, а фасоль DataSource должен существовать, и фасоль автоматически зарегистрирован.
Введите класс DataSourceAutoConfiguration, вы увидите, что этот класс принадлежит этому пакету:
org.springframework.boot.autoconfigure.jdbc
Этот пакет относится к пакету spring-boot-autoconfigure-2.0.4.RELEASE.jar, В пакете автоматической настройки представлены пакеты jdbc, kafka, logging, mail, mongo и другие. Многие пакеты должны быть автоматически настроены после того, как мы введем соответствующий jar, чтобы они вступили в силу.
3. Получение параметров Bean
Пока мы уже знаем процесс настройки bean-компонента, но мы не видели, как springboot считывает свойства файла конфигурации yml или properties для создания источника данных?
В классе DataSourceAutoConfiguration мы заметили использование аннотации EnableConfigurationProperties.
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,
DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
@Configuration
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedDatabaseConfiguration {
}
......
Свойства источника данных инкапсулированы в DataSourceProperties, а префикс файла конфигурации указывается с помощью аннотации ConfigurationProperties.
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
private ClassLoader classLoader;
/**
* Name of the datasource. Default to "testdb" when using an embedded database.
*/
private String name;
/**
* Whether to generate a random datasource name.
*/
private boolean generateUniqueName;
/**
* Fully qualified name of the connection pool implementation to use. By default, it
* is auto-detected from the classpath.
*/
private Class<? extends DataSource> type;
/**
* Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.
*/
private String driverClassName;
/**
* JDBC URL of the database.
*/
private String url;
/**
* Login username of the database.
*/
private String username;
/**
* Login password of the database.
*/
private String password;
/**
* JNDI location of the datasource. Class, url, username & password are ignored when
* set.
*/
private String jndiName;
/**
* Initialize the datasource with available DDL and DML scripts.
*/
private DataSourceInitializationMode initializationMode = DataSourceInitializationMode.EMBEDDED;
/**
* Platform to use in the DDL or DML scripts (such as schema-${platform}.sql or
* data-${platform}.sql).
*/
private String platform = "all";
/**
* Schema (DDL) script resource references.
*/
private List<String> schema;
/**
* Username of the database to execute DDL scripts (if different).
*/
private String schemaUsername;
/**
* Password of the database to execute DDL scripts (if different).
*/
private String schemaPassword;
/**
* Data (DML) script resource references.
*/
private List<String> data;
......
Благодаря приведенному выше анализу мы можем узнать, что:
Роль аннотации @ConfigurationProperties заключается в преобразовании файла конфигурации yml или свойств в bean-компонент.
Роль аннотации @EnableConfigurationProperties состоит в том, чтобы сделать аннотацию @ConfigurationProperties эффективной. Если настроена только аннотация @ConfigurationProperties, bean-компонент, преобразованный из файла конфигурации yml или properties, не может быть получен в контейнере spring.
Таким образом, параметры конфигурации yml или properties преобразуются в bean-компоненты, и как эти bean-компоненты обнаруживаются и загружаются?
4. Открытие Бина
По умолчанию springboot сканирует все компоненты основного класса и подклассов в пакете, в котором находится класс запуска, но не включает классы в зависимом пакете, так как же обнаруживаются и загружаются bean-компоненты в зависимом пакете?
Обычно мы добавляем аннотацию @SpringBootApplication в класс запуска, нажмите, чтобы увидеть
@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 {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
......
На самом деле имеют значение только три аннотации:
- @Configuration (@Configuration по-прежнему применяется в @SpringBootConfiguration)
- @EnableAutoConfiguration
- @ComponentScan
Роль @Configuration Мы уже знаем выше, что аннотированный класс станет классом конфигурации компонента.
Роль @ComponentScan заключается в автоматическом сканировании и загрузке подходящих компонентов, таких как @Component и @Repository, и, наконец, в загрузке этих определений bean-компонентов в контейнер Spring.
Функция аннотации @EnableAutoConfiguration очень важна, благодаря поддержке @Import она собирает и регистрирует связанные определения bean-компонентов в зависимых пакетах.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
Как и в приведенном выше исходном коде, аннотация @EnableAutoConfiguration вводит две аннотации: @AutoConfigurationPackage и @Import. Роль @AutoConfigurationPackage заключается в автоматической настройке пакета, а @Import импортирует компоненты, которые необходимо настроить автоматически.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
~
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
new AutoConfigurationPackages.PackageImport(metadata)).getPackageName() new AutoConfigurationPackages.PackageImport(metadata)
Функция этих двух строк кода состоит в том, чтобы загрузить все компоненты основного класса и подкласса в пакете, где находится класс запуска, и зарегистрировать их в контейнере Spring.Это сканирование по умолчанию основного класса и подкласса в пакете где находится класс запуска Все компоненты.
Тогда снова возникает вопрос, откуда берутся бобы, которые нужно собрать и зарегистрировать в контейнере Spring?
Войдя в класс AutoConfigurationImportSelector, мы можем обнаружить, что метод SpringFactoriesLoader.loadFactoryNames вызывает метод loadSpringFactories для чтения информации файла META-INF/spring.factories из всех пакетов jar.
Ниже приведена часть файла spring.factories в jar spring-boot-autoconfigure.Существует ключевое значение org.springframework.boot.autoconfigure.EnableAutoConfiguration, определяющее bean-компоненты, которые необходимо настроить автоматически.Прочитав эту конфигурацию, группа класса @ Configuration.
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
Каждый xxxAutoConfiguration является классом конфигурации bean-компонента на основе Java. На самом деле не все эти xxxAutoConfiguratios будут загружены и будут загружены в соответствии с такими условиями, как @ConditionalOnClass в xxxAutoConfiguration; класс @Configuration в spring.factories создается как соответствующий столбец экземпляра java с помощью механизма отражения.
Теперь, когда мы знаем, как обнаружить bean-компоненты для автоматической настройки, последний шаг — загрузить эти bean-компоненты в контейнер Spring.
5. Загрузка бобов
Если вы хотите, чтобы общий класс управлялся контейнером Spring, обычно существуют следующие методы:
- Использование аннотаций @Configuration и @Bean
- Аннотируйте класс аннотацией @Controller @Service @Repository @Component, затем включите @ComponentScan для автоматического сканирования
- Использование метода @Import
Метод @Import используется в Springboot.
В аннотации @EnableAutoConfiguration используется аннотация @Import({AutoConfigurationImportSelector.class}).AutoConfigurationImportSelector реализует интерфейс DeferredImportSelector.
Интерфейс DeferredImportSelector наследует интерфейс ImportSelector, а интерфейс ImportSelector имеет только один метод selectImports.
Метод selectImports возвращает набор bean-компонентов.Аннотация @EnableAutoConfiguration внедряет этот набор bean-компонентов в контейнер Spring с помощью аннотации @Import.Springboot официально завершает внедрение bean-компонентов через этот механизм.
4. Резюме
Мы можем резюмировать ключевые шаги автоматической настройки и соответствующие аннотации следующим образом:
- @Configuration& и @Bean------>>> конфигурация bean-компонента на основе кода Java
- @Conditional-------->>>>>> установить условные зависимости автоконфигурации
- @EnableConfigurationProperties с @ConfigurationProperties -> читать файлы конфигурации в bean-компоненты.
- @EnableAutoConfiguration, @AutoConfigurationPackage и @Import-> реализуют обнаружение и загрузку компонентов.
Приветствую всех желающих пообщаться с вами.Если вам понравилась статья, не забудьте поставить лайк.Спасибо за вашу поддержку!