Статьи собраны на GitHubJavaEggMedium, добро пожаловать в подсказки со звездочкой+
JavaEgg——«Java Technician» Руководство по развитию, включая основы Java, структуру, хранение, поиск, оптимизацию, распространение и другие необходимые знания, спектр основных навыков разработки N-line в Интернете.
Источник примечания: Shang Silicon Valley Teaching Notes.
1. Привет весенняя загрузка
1. Введение в Spring Boot
- Фреймворк для упрощения разработки приложений Spring;
- Большая интеграция всего стека технологий Spring;
- Универсальное решение для разработки J2EE;
2. Микросервисы
- Микросервисы: архитектурный стиль (микроизация сервисов)
- Приложение должно представлять собой набор небольших сервисов, оно может общаться друг с другом через HTTP;
- Монолитное приложение: ВСЕ В ОДНОМ
- Микросервисы: каждый функциональный элемент в конечном итоге представляет собой программную единицу, которую можно независимо заменять и обновлять;Дополнительные сведения см. в документации по микросервисам.
3, подготовка среды
- jdk1.8: Spring Boot рекомендует jdk1.7 и выше, версия Java "1.8.0_112"
- maven3.x: maven 3.3 или выше, Apache Maven 3.3.9
- IntelliJIDEA, СТС
- SpringBoot 2.2.2.RELEASE, унифицированная среда;
3.1 Настройки MAVEN;
Добавьте в тег profiles файл конфигурации maven settings.xml.
<profile>
<id>jdk‐1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
3.2, настройки IDEA
Интегрировать maven в
3.3 Spring Boot HelloWorld
Реализовать небольшую функцию: браузер отправляет приветственный запрос, сервер принимает запрос и обрабатывает его, и отвечает на строку Hello World;
1,Создаватьmavenпроект;(jar)
2, Импортироватьspring bootсвязанные зависимости
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
</dependency>
</dependencies>
3, написать основную программу; запуститьSpring Bootприменение
/**
* @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
// Spring应用启动起来
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}
4, напишите по темеController,Service
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public String hello(){
return "Hello World!";
}
}
5, запустить основной метод основной программы, протестировать
6, упростить развертывание
<!‐‐ 这个插件,可以将应用打包成一个可执行的jar包;‐‐>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐maven‐plugin</artifactId>
</plugin>
</plugins>
</build>
Введите это приложение в пакет jar и запустите его напрямую с помощью команды java -jar.java -jar HelloWorldMainApplication.jar
3.4, привет исследование мира
3.4.1. POM-файл
-
родительский проект
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter‐parent</artifactId> <version>2.2.2.RELEASE</version> </parent>
Войдите в родительский проект, вы можете увидеть родительский проект родительского проекта (проект дедушки)
<!-- 爷爷项目(他的父项目)是 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐dependencies</artifactId> <version>2.2.2.RELEASE</version> <relativePath>../../spring‐boot‐dependencies</relativePath> </parent>
Он фактически управляет всеми версиями зависимостей в приложении Spring Boot; даАрбитражный центр версии Spring Boot;
В дальнейшем, когда мы будем импортировать зависимости, нам не нужно будет писать версии по умолчанию.; (Зависимости, которые не управляются в зависимостях, естественно, должны объявлять номер версии)
-
Пусковая установка
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter‐web</artifactId> </dependency>
spring-boot-starter-web:
spring-boot-starter: запуск сцены spring-boot, помогает нам импортировать компоненты, от которых веб-модуль зависит для нормальной работы;
Spring Boot извлекает все функциональные сценарии и превращает их в стартеры (стартеры) один за другим, вам нужно только ввести эти стартеры в проект.
Будут импортированы все зависимости связанных сцен. Лаунчер для импорта любой сцены с любой функцией
3.4.2, основной класс программы, основной класс входа (следите за притворством, чтобы щелкнуть, посмотреть исходный код и стать новичком, прочитавшим исходный код)
/**
* @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
// Spring应用启动起来
SpringApplication.run(HelloWorldMainApplication.class, args);
}
}
@SpringBootApplication: аннотация приложения Spring Boot для класса указывает, что этот класс является основным классом конфигурации Spring Boot, Spring Boot
Вы должны запустить основной метод этого класса, чтобы запустить приложение SpringBoot;
@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 {
@SpringBootConfiguration: класс конфигурации Spring Boot, помеченный на классе, указывающий, что это класс конфигурации Spring Boot;
@Конфигурация: используется, чтобы пометить это как класс конфигурации;
@Включить автоконфигурацию: включить функцию автоматической настройки;
Прежде чем нам нужно было что-то настроить, Spring Boot помог нам настроить их автоматически; @Включить автоконфигурациюСкажите SpringBoot включить функцию автоматической настройки, чтобы автоматическая настройка вступила в силу;
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
@Пакет автоконфигурации: Пакет автоматической настройки
Базовая аннотация Spring **@Import** импортирует компонент в контейнер; импортированный компонент определяется AutoConfigurationImportSelector.class
Сканировать пакет, содержащий основной класс конфигурации (класс, отмеченный @SpringBootApplication) и все компоненты во всех следующих подпакетах, в контейнер Spring;
@Import(EnableAutoConfigurationImportSelector.class); Импортировать компоненты в контейнер?
AutoConfigurationImportSelector: селектор компонентов для импорта;
Верните все компоненты, которые необходимо импортировать, как полные имена классов, эти компоненты будут добавлены в контейнер;
Он будет импортировать в контейнер множество классов автоматической настройки (xxxAutoConfiguration), он заключается в том, чтобы импортировать в контейнер все компоненты, необходимые для этой сцены, и настраивать эти компоненты;
С классом автоматической конфигурации мы избавляемся от необходимости вручную писать компоненты функции внедрения конфигурации и т. д.;
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Spring Boot начинается с пути к классам изMETA-INF/spring.factoriesПолучите значения, указанные EnableAutoConfiguration в , и импортируйте эти значения в контейнер как классы автоматической конфигурации. Классы автоматической конфигурации вступят в силу и помогут нам выполнить автоматическую настройку. Прежде чем нам нужно было настраивать вещи самостоятельно, автоматический классы конфигурации помогли нам настроить их;
Общее решение по интеграции и автоматическая настройка J2EE находятся в файле spring-boot-autoconfigure-2.2.2.RELEASE.jar;
3.5 Используйте Spring Initializer для быстрого создания проектов Spring Boot
-
ИДЕЯ: можно использоватьSpring InitializerБыстро создавайте проекты
Все IDE поддерживают использование мастера создания проекта Spring для быстрого создания проекта Spring Boot, выбора необходимых модулей, мастера создаст проект Spring Boot в режиме онлайн;
Сгенерированный по умолчанию проект Spring Boot;
- Основная программа сгенерирована, нам нужна только собственная логика
- Структура каталогов в папке ресурсов
- статические: сохранить все статические ресурсы, js css изображения;
- шаблоны: сохраняет все страницы шаблонов (по умолчанию jar-пакет Spring Boot использует встроенный Tomcat, страницы JSP по умолчанию не поддерживаются); можно использовать механизмы шаблонов (freemarker, thymeleaf);
- application.properties: файл конфигурации приложения Spring Boot, некоторые настройки по умолчанию могут быть изменены;
-
STSиспользоватьSpring Starter ProjectБыстро создавайте проекты
2. Файл конфигурации
1, конфигурационный файл
SpringBoot использует глобальный файл конфигурации, а имя файла конфигурации фиксировано (есть две формы);
- application.properties
- application.yml
Роль файла конфигурации: изменить значение по умолчанию для автоматической настройки SpringBoot; (SpringBoot автоматически настраивает нас внизу)
YAML(YAML не является языком разметки) YAML Язык разметки:язык разметки
YAML: ориентирован на данные, больше подходит для конфигурационных файлов, чем json, xml и т. д.;
предыдущие файлы конфигурации; в основном используетсяxxxx.xmlфайл; например:
YAML: пример конфигурации
server:
port: 8080
Пример XML:
<server>
<port>8080</port>
</server>
2. Синтаксис YAML:
1. Базовая грамматика
k: (пробел) v: представляет пару пар ключ-значение (пробелы должны присутствовать);
Управляйте иерархическими отношениями с помощью отступов пробелов; пока это столбец данных, выровненный по левому краю, все они находятся на одном уровне
server:
port: 8080
path: /hello
Свойства и значения чувствительны к регистру;
2, написание значения
Литерал: простое значение (число, строка, логическое значение)
k:v: пиши буквально;
Строки не нужно добавлять одинарные или двойные кавычки по умолчанию;
""
: двойные кавычки; специальные символы в строке не экранируются; специальные символы будут использоваться как значение, которое они хотят выразить name: "zhangsan \n lisi": вывод; zhangsan новая строка lisi
''
: одинарная кавычка; специальные символы экранируются, а специальные символы становятся обычной строкой данных.
имя: 'zhangsan \n lisi': вывод; zhangsan \n lisi
Объект, Карта (свойство и значение) (пара ключ-значение):
k: v
: Чтобы написать взаимосвязь между атрибутами и значениями объекта на следующей строке; Примечание отступ
Объект по-прежнему k:v путь
friends:
lastName: zhangsan
age: 20
Встроенное письмо:
friends: {lastName: zhangsan,age: 20}
Массивы (список, набор):
использовать-
значение представляет элемент в массиве
pets:
‐ cat
‐ dog
‐ pig
Встроенное письмо
pets: [cat,dog,pig]
3, вставка значения файла конфигурации
3.1. Конфигурационный файл:
person:
lastName: hello
age: 18
boss: false
birth: 2017/12/12
maps: {k1: v1,k2: 12}
lists:
‐ lisi
‐ zhaoliu
dog:
name: 小狗
age: 12
3.2, JavaBean:
/**
* 将配置文件中配置的每一个属性的值,映射到这个组件中
* @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
* prefix = "person":配置文件中哪个下面的所有属性进行一一映射
*
* 只有这个组件是容器中的组件,才能使用容器提供的@ConfigurationProperties功能;
*
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
Мы можем импортировать файл конфигурации процессора, и при записи конфигурации позже будет подсказка.
<!‐‐导入配置文件处理器,配置文件进行绑定就会有提示‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐configuration‐processor</artifactId>
<optional>true</optional>
</dependency>
3.3 Разница между значением, полученным с помощью @Value, и значением, полученным с помощью @ConfigurationProperties
@ConfigurationProperties | @Value | |
---|---|---|
Функции | Массовое внедрение свойств в конфигурационные файлы | Один обозначен |
свободная привязка (свободный синтаксис) | служба поддержки | не поддерживается |
SpEL | не поддерживается | служба поддержки |
Проверка данных JSR303 | служба поддержки | не поддерживается |
инкапсуляция сложного типа | служба поддержки | не поддерживается |
-
Они могут получить значение файла конфигурации yml или свойства;
-
Если нам просто нужно получить определенное значение в конфигурационном файле в определенной бизнес-логике, используйте @Value;
-
Если мы говорим, что специально написали javaBean для сопоставления с файлом конфигурации, мы будем использовать @ConfigurationProperties напрямую;
3.4. Проверка данных значения инъекции файла конфигурации
@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
/**
* <bean class="Person">
* <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#
{SpEL}"></property>
* <bean/>
*/
//lastName必须是邮箱格式
@Email
//@Value("${person.last‐name}")
private String lastName;
//@Value("#{11*2}")
private Integer age;
//@Value("true")
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
3.5, @PropertySource&@ImportResource&@Bean
@PropertySource: загрузить указанный файл конфигурации;
/**
* 将配置文件中配置的每一个属性的值,映射到这个组件中
* @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
* prefix = "person":配置文件中哪个下面的所有属性进行一一映射
*
* 只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能;
* @ConfigurationProperties(prefix = "person")默认从全局配置文件中获取值;
*
*/
@PropertySource(value = {"classpath:person.properties"})
@Component
@ConfigurationProperties(prefix = "person")
//@Validated
public class Person {
/**
* <bean class="Person">
* <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#
{SpEL}"></property>
* <bean/>
*/
//lastName必须是邮箱格式
// @Email
//@Value("${person.last‐name}")
private String lastName;
//@Value("#{11*2}")
private Integer age;
//@Value("true")
private Boolean boss;}
@ImportResource: импортируйте файл конфигурации Spring, чтобы содержимое файла конфигурации вступило в силу;
В Spring Boot нет конфигурационного файла Spring, а конфигурационный файл, который мы написали сами, не может быть автоматически распознан, я хочу Spring
Файл конфигурации вступает в силу и загружается; вам нужно отметить @ImportResource в классе конфигурации и импортировать файл конфигурации Spring, чтобы он вступил в силу
@ImportResource(locations = {"classpath:beans.xml"})
Пользовательский файл конфигурации Spring
<?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.xsd">
<bean id="helloService" class="com.atguigu.springboot.service.HelloService"></bean>
</beans>
SpringBoot рекомендует способ добавления компонентов в контейнер, рекомендуется использовать метод полной аннотации
-
Класс конфигурации **@Configuration**------>Файл конфигурации Spring
-
Используйте **@Bean** для добавления компонентов в контейнер
/** * @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件 * 在配置文件中用<bean><bean/>标签添加组件 */ @Configuration public class MyAppConfig { //将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名 @Bean public HelloService helloService02(){ System.out.println("配置类@Bean给容器中添加组件了..."); return new HelloService(); } }
3.6, заполнитель файла конфигурации
1,случайный номер
${random.value}、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}
2, заполнитель для получения ранее настроенного значения, если нет, его можно использовать:
Укажите значение по умолчанию
person.last‐name=张三${random.uuid}
person.age=${random.int}
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=${person.hello:hello}_dog
person.dog.age=15
3.7 Профиль
3.7.1 Несколько файлов профилей
Когда мы пишем основной файл конфигурации, имя файла может бытьприложение-{профиль}.properties/yml
Конфигурация application.properties используется по умолчанию;
3.7.2, yml поддерживает многодокументный блочный режим
server:
port: 8081
spring:
profiles:
active: prod
‐‐‐
server:
port: 8083
spring:
profiles: dev
‐‐‐
server:
port: 8084
spring:
profiles: prod #指定属于哪个环境
3.7.3 Активировать указанный профиль
1. Указать в конфигурационном файлеФайлы spring.pro.active = dev
2. Командная строка:
java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
; Вы можете настроить входящие параметры командной строки непосредственно при тестировании
3. Параметры виртуальной машины;
-Dspring.profiles.active=dev
3.8 Место загрузки конфигурационного файла
Запуск Springboot будет сканировать файлы application.properties или application.yml в следующих местах в качестве файлов конфигурации по умолчанию для загрузки Spring.
- файл:./config/
- файл:./
- путь к классам:/config/
- classpath:/
Приоритет идет сверху вниз, и конфигурация с высоким приоритетом имеет приоритет над конфигурацией с низким приоритетом;
SpringBoot загрузит все основные файлы конфигурации из этих четырех мест: дополнительная конфигурация;
Мы также можем пройтиspring.config.locationизменить расположение файла конфигурации по умолчанию
После того, как проект упакован, мы можем использовать форму параметров командной строки, чтобы указать новое расположение файла конфигурации при запуске проекта, указанный файл конфигурации и загруженные по умолчанию файлы конфигурации работают вместе, чтобы сформировать дополнительную конфигурацию;
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties
3.9 Порядок загрузки внешней конфигурации
SpringBootКонфигурации также можно загружать из следующих расположений: приоритет от высокого к низкому; конфигурации с высоким приоритетом переопределяют конфигурации с низким приоритетом, и все конфигурации образуют дополнительные конфигурации.
-
аргументы командной строки
Все конфигурации можно указать в командной строке
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc
Несколько конфигураций разделяются пробелами;--config элемент=значение
-
Свойства JNDI из java:comp/env
-
Системные свойства Java (System.getProperties())
-
переменные среды операционной системы
-
random.* значения свойств, настроенные RandomValuePropertySource
Зависит отjarИсходящийjarНайдите в упаковке, сначала загрузите лентупрофиль
- jarвне пакетаприложение-{профиль}.propertiesили **application.yml(поясspring.profile)** конфигурационный файл
- jarвнутри пакетаприложение-{профиль}.propertiesили **application.yml(поясspring.profile)** конфигурационный файл
загрузить снова безпрофиль
-
Файл конфигурации application.properties или application.yml (без spring.profile) вне пакета jar.
-
jarвнутри пакетаapplication.propertiesили **application.yml(Безspring.profile)** конфигурационный файл
10. @PropertySource в аннотированных классах @Configuration
11. Все поддерживаемые источники загрузки конфигурации через свойства по умолчанию, указанные SpringApplication.setDefaultProperties;
Обратитесь к официальной документации
3.10 Принцип автоматической настройки
Что именно может написать конфигурационный файл? как писать? Принцип автоматической настройки;Атрибуты, которые можно настроить в файле конфигурации, относятся к
3.10.1 Принцип автоматической настройки:
1) Основной класс конфигурации загружается при запуске SpringBoot, и функция автоматической настройки включена @EnableAutoConfiguration
2),@EnableAutoConfigurationэффект:
-
Используйте AutoConfigurationImportSelector для импорта некоторых компонентов в контейнер.
-
Вы можете просмотреть содержимое метода selectImports();
-
Список конфигураций = getCandidateConfigurations(annotationMetadata, атрибуты); Получить конфигурации-кандидаты
SpringFactoriesLoader.loadFactoryNames()
Сканировать все пакеты jar в пути к классамMETA‐INF/spring.factories
, оберните содержимое этих отсканированных файлов в объекты свойств
Получить из свойствEnableAutoConfiguration.class
значения, соответствующие классу (имя класса), а затем добавить их в контейнер
середина
поставить путь к классамMETA-INF/spring.factoriesВся конфигурация внутриВключить автоконфигурациюЗначение добавляется в контейнер;
# 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,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,
\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration
,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration
,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration
Каждый такой класс xxxAutoConfiguration является компонентом в контейнере и добавляется в контейнер, используйте их для автоматической настройки;
3) каждый класс автоматической конфигурации выполняет функцию автоматической конфигурации;
4), возьмите HttpEncodingAutoConfiguration (автоматическая настройка кодирования HTTP) в качестве примера, чтобы объяснить принцип автоматической настройки;
@Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
@EnableConfigurationProperties(HttpEncodingProperties.class) //启动指定类的
//ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把
// HttpEncodingProperties加入到ioc容器中
@ConditionalOnWebApplication //Spring底层@Conditional注解(Spring注解版),根据不同的条件,如 //果满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnClass(CharacterEncodingFilter.class) //判断当前项目有没有这个类
// CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) //判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
public class HttpEncodingAutoConfiguration {
//他已经和SpringBoot的配置文件映射了
private final HttpEncodingProperties properties;
//只有一个有参构造器的情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
@ConditionalOnMissingBean(CharacterEncodingFilter.class) //判断容器没有这个组件?
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
В соответствии с различными текущими условиями определите, действует ли этот класс конфигурации.
Как только этот класс конфигурации вступит в силу, этот класс конфигурации добавит в контейнер различные компоненты, свойства этих компонентов будут получены из соответствующего класса свойств, и каждое свойство в этих классах привязано к файлу конфигурации;
5) Все свойства, которые можно настроить в файле конфигурации, инкапсулированы в класс xxxxProperties; то, что можно настроить в файле конфигурации, может относиться к классу свойств, соответствующему функции.
@ConfigurationProperties(prefix = "spring.http.encoding") //从配置文件中获取指定的值和bean的属
性进行绑定
public class HttpEncodingProperties {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF‐8");
Сущность:
1),SpringBootАвтозагрузка загружает много классов автоконфигурации
2), посмотрим, доступны ли нужные нам функцииSpringBootКласс автоматической настройки написан по умолчанию;
3), давайте посмотрим, какие компоненты настроены в этом классе автоматической настройки; (пока есть компоненты, которые мы используем, нам не нужно их настраивать заново)
4), при добавлении компонентов в класс автоконфигурации в контейнере он будет начинаться сpropertiesПолучить некоторые свойства из класса. Мы можем указать значения этих свойств в файле конфигурации;
xxxxAutoConfigurartion: класс автоматической настройки; добавление компонентов в контейнер
xxxxProperties: связанные свойства в файле конфигурации пакета;
3.10.2 Детали
1,@ConditionalПроизводные аннотации (SpringСобственная функция **@Conditional** аннотированной версии)
Функция: Только когда условия, указанные @Conditional, будут установлены, компоненты будут добавлены в контейнер, и все содержимое в конфигурации вступит в силу;
@ConditionalРасширенная аннотация | Функция (оценка выполнения текущих заданных условий) |
---|---|
@ConditionalOnJava | Соответствует ли java-версия системы требованиям |
@ConditionalOnBean | Указанный bean-компонент существует в контейнере; |
@ConditionalOnMissingBean | Указанный компонент не существует в контейнере; |
@ConditionalOnExpression | Удовлетворить спецификации выражения SpEL |
@ConditionalOnClass | В системе есть указанный класс |
@ConditionalOnMissingClass | В системе не указан класс |
@ConditionalOnSingleCandidate | В контейнере находится только один указанный компонент, или этот компонент является предпочтительным компонентом. |
@ConditionalOnProperty | Имеет ли свойство, указанное в системе, указанное значение |
@ConditionalOnResource | Существует ли указанный файл ресурсов в пути к классам |
@ConditionalOnWebApplication | текущая веб-среда |
@ConditionalOnNotWebApplication | В настоящее время не является веб-средой |
@ConditionalOnJndi | JNDI существование указанного элемента |
Классы автоконфигурации должны действовать при определенных условиях, как узнать, какие классы автоконфигурации действуют;
Мы можем включитьdebug=trueсвойство, позволяющее консоли распечатать отчет об автоконфигурации, чтобы мы могли легко узнать, какие классы автоконфигурации действуют;
=========================
AUTO‐CONFIGURATION REPORT
=========================
Positive matches:(自动配置类启用的)
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
DispatcherServletAutoConfiguration matched:
‐ @ConditionalOnClass found required class
'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find
unwanted class (OnClassCondition)
‐ @ConditionalOnWebApplication (required) found StandardServletEnvironment
(OnWebApplicationCondition)
Negative matches:(没有启动,没有匹配成功的自动配置类)
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
ActiveMQAutoConfiguration:
Did not match:
‐ @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory',
'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
AopAutoConfiguration:
Did not match:
‐ @ConditionalOnClass did not find required classes
'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition)
3. Журнал
Подробное введение в журнал и использование logback click -->Очистить все виды журналирования Java
1, структура ведения журнала
У Java Great Ape Shuai давным-давно был менталитет и процесс разработки крупномасштабной системы;
1. System.out.println(""); вывести данные ключа на консоль; удалить? записать в файл?
2. Фреймворк для записи некоторой информации о системе во время выполнения, лог-фреймворк, biglogging.jar;
3. Сколько функций у Талля? Асинхронный режим? Автоматическая подача? хххх? biglogging-good.jar?
4. Удалить предыдущий кадр? Перейдите на новый фреймворк и повторно измените предыдущий связанный API, biglogging-prefect.jar;
5. JDBC --- драйвер базы данных;
6. Написал унифицированный слой интерфейса, лог-фасад (абстракция логов), logging-abstract.jar, просто импортируем в проект конкретные реализации логов, наши предыдущие фреймворки логов — это абстрактные слои реализации;
Фреймворки для логирования на рынке;
JUL, JCL, Jboss-логирование, logback, log4j, log4j2, slf4j....
Бревенчатый фасад (слой абстракции для бревен) | реализация журнала |
---|---|
JCL (Jakarta Commons Logging), SLF4j (простой фасад ведения журнала для Java), jboss-logging | Log4j, июль (java.util.logging), Log4j2Logback |
Выбираем фасад (абстрактный слой) слева и реализацию справа; выбираю два с завязанными глазами наугад, лог-фасад: SLF4J, лог-реализация: Logback (он же конструктор SpringBoot, и герой видит то же самое. Ах);
SpringBoot: нижний уровень — это среда Spring, а среда Spring по умолчанию использует JCL;SpringBootвыберитеSLF4jиlogback;
2. Использование SLF4j
1. Как использовать в системеSLF4j
В будущей разработке вызов метода ведения журнала должен вызывать не напрямую класс реализации журнала, а вызывать метод в слое абстракции журнала; импортировать jar slf4j и jar реализации logback в систему
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
Каждая структура реализации журнала имеет свой собственный файл конфигурации. После использования slf4j,Файл конфигурации по-прежнему включен в файл конфигурации самой структуры реализации журнала;
2, Оставшаяся проблема
SpringBoot (slf4j+logback): Spring (журналирование общих ресурсов), Hibernate (логирование jboss), MyBatis, xxxx
Унифицированное ведение журнала, даже если другие фреймворки используют slf4j вместе со мной для вывода?
Как сделать все журналы в системе едиными дляslf4j;
1. Сначала исключите другие фреймворки журналов в системе;
2. Заменить исходную структуру ведения журнала промежуточным пакетом;
3. Импортируем другие реализации slf4j
3, Связь с журналом SpringBoot
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter</artifactId>
</dependency>
SpringBoot использует его для ведения журнала;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐logging</artifactId>
</dependency>
Суммировать:
-
Нижний уровень SpringBoot также использует slf4j+logback для логирования.
-
SpringBoot также заменил другие журналы на slf4j;
-
Промежуточный сменный пакет
@SuppressWarnings("rawtypes") public abstract class LogFactory { static String UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J = "http://www.slf4j.org/codes.html#unsupported_operation_in_jcl_over_slf4j"; static LogFactory logFactory = new SLF4JLogFactory();
-
Что, если мы захотим ввести другие фреймворки? Обязательно удалите зависимость ведения журнала по умолчанию для этой платформы.
Фреймворк Spring использует ведение журнала общих ресурсов;
<dependency> <groupId>org.springframework</groupId> <artifactId>spring‐core</artifactId> <exclusions> <exclusion> <groupId>commons‐logging</groupId> <artifactId>commons‐logging</artifactId> </exclusion> </exclusions> </dependency>
SpringBootОн может автоматически адаптироваться ко всем журналам, а нижний слой используетslf4j+logbackКогда вы вводите другие фреймворки, вам нужно только исключить фреймворк журналов, от которого зависит этот фреймворк;
4, использование журнала
4.1 Конфигурация по умолчанию
SpringBoot по умолчанию настраивает журнал за нас;
//记录器
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void contextLoads() {
//System.out.println();
//日志的级别;
//由低到高 trace<debug<info<warn<error
//可以调整输出的日志级别;日志就只会在这个级别以以后的高级别生效
logger.trace("这是trace日志...");
logger.debug("这是debug日志...");
//SpringBoot默认给我们使用的是info级别的,没有指定级别的就用SpringBoot默认规定的级别;root
级别
logger.info("这是info日志...");
logger.warn("这是warn日志...");
logger.error("这是error日志...");
}
日志输出格式:
%d表示日期时间,
%thread表示线程名,
%‐5level:级别从左显示5个字符宽度
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息,
%n是换行符
‐‐>
%d{yyyy‐MM‐dd HH:mm:ss.SSS} [%thread] %‐5level %logger{50} ‐ %msg%n
Конфигурация журнала изменений SpringBoot по умолчанию
logging.level.cn.starfish=trace
#logging.path=
# 不指定路径在当前项目下生成springboot.log日志
# 可以指定完整的路径;
#logging.file=G:/springboot.log
# 在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用 spring.log 作为默认文件
logging.path=/spring/log
# 在控制台输出的日志的格式
logging.pattern.console=%d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n
# 指定文件中日志输出的格式
logging.pattern.file=%d{yyyy‐MM‐dd} === [%thread] === %‐5level === %logger{50} ==== %msg%n
лог.файл | logging.path | Example | Description |
---|---|---|---|
(none) | (none) | вывод только в консоль | |
указать имя файла | (none) | my.log | Вывод журнала в файл my.log |
(none) | указанный каталог | /var/log | Вывод в файл spring.log в указанном каталоге |
4.2. Укажите конфигурацию
Просто поместите собственный файл конфигурации каждой среды ведения журнала в путь к классам; SpringBoot не использует его конфигурацию по умолчанию.
Logging System | Customization |
---|---|
Logback | logback-spring.xml , logback-spring.groovy , logback.xml or logback.groovy |
Log4j2 | log4j2-spring.xml or log4j2.xml |
JDK (Java Util Logging) | logging.properties |
logback.xml: он напрямую распознается фреймворком ведения журнала;
logback-spring.xml: структура журнала не загружает элементы конфигурации журнала напрямую. SpringBoot анализирует конфигурацию журнала. Вы можете использовать SpringBoot
Расширенные функции профиля
<springProfile name="staging">
<!‐‐ configuration to be enabled when the "staging" profile is active ‐‐>
可以指定某段配置只在某个环境下生效
</springProfile>
как:
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!‐‐
日志输出格式:
%d表示日期时间,
%thread表示线程名,
%‐5level:级别从左显示5个字符宽度
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息,
%n是换行符
‐‐>
<layout class="ch.qos.logback.classic.PatternLayout">
<springProfile name="dev">
<pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ‐‐‐‐> [%thread] ‐‐‐> %‐5level
%logger{50} ‐ %msg%n</pattern>
</springProfile>
<springProfile name="!dev">
<pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ==== [%thread] ==== %‐5level
%logger{50} ‐ %msg%n</pattern>
</springProfile>
</layout>
</appender>
Если вы используете logback.xml в качестве файла конфигурации журнала, а также используете функцию профиля, будут следующие ошибки
no applicable action for [springProfile]
5, переключить структуру ведения журнала
Сопутствующее переключение может быть выполнено в соответствии со схемой адаптации журнала slf4j;
способ slf4j+log4j;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>logback‐classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
<exclusion>
<artifactId>log4j‐over‐slf4j</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j‐log4j12</artifactId>
</dependency>
переключиться на log4j2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring‐boot‐starter‐logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐log4j2</artifactId>
</dependency>
4. Веб-разработка
1. Использование SpringBoot
1),СоздайтеSpringBootПодать заявку, выбрать нужный нам модуль;
2),SpringBootЭти сценарии были настроены по умолчанию, и вам нужно указать только небольшую часть конфигурации в файле конфигурации для запуска.
3), я написал бизнес-код;
2, правила отображения SpringBoot для статических ресурсов;
Продирая SpringBoot к ResourceProperties слой за слоем, можно увидеть последовательность путей загрузки ресурсов, а также некоторые цепочки операций свойств (версия SpringBoot1.xx наследует ResourceLoaderAware, 2.xx и 1.xx изменения довольно голодны).
-
Все /webjars/** , перейдите по пути к классам:/META-INF/resources/webjars/, чтобы найти ресурсы;
webjars: Импорт статических ресурсов в виде пакетов jar;
localhost:8080/webjars/jquery/3.3.1/jquery.js
<!‐‐引入jquery‐webjar‐‐>在访问的时候只需要写webjars下面资源的名称即可
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
-
"/**" Чтобы получить доступ к любому ресурсу текущего проекта, перейдите в (папку статического ресурса), чтобы найти сопоставление
"путь к классам:/META-INF/ресурсы/", "путь к классам:/ресурсы/", "путь к классам:/статический/", "путь к классам:/публичный/" "/": корневой путь текущего проекта
localhost:8080/abc === 去静态资源文件夹里面找abc
- 欢迎页; 静态资源文件夹下的所有index.html页面;被"/**"映射;
localhost:8080/ 找index页面
- 所有的 **/favicon.ico 都是在静态资源文件下找;
## **3**、模板引擎
常见的模板引擎:JSP、Velocity、Freemarker、Thymeleaf
![template.png](http://ww1.sinaimg.cn/large/9b9f09a9ly1ga268zn2bxj20hy08b0t0.jpg)
SpringBoot推荐的Thymeleaf; 语法更简单,功能更强大;
### 3.1、引入thymeleaf;
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐thymeleaf</artifactId>
</dependency>
<!--切换thymeleaf版本-->
<properties>
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<!‐‐布局功能的支持程序 thymeleaf3主程序 layout2以上版本‐‐>
<!‐‐ thymeleaf2 layout1‐‐>
<thymeleaf‐layout‐dialect.version>2.2.2</thymeleaf‐layout‐dialect.version>
</properties>
3.2, Использование листьев тимьяна
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = Charset.forName("UTF‐8");
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
Пока мы помещаем HTML-страницу в classpath:/templates/, тимелеаф может автоматически отображать;
-
Импортировать пространство имен тимелеафа
<html lang="en" xmlns:th="http://www.thymeleaf.org">
-
Используйте синтаксис тимелеафа;
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF‐8"> <title>Title</title> </head> <body> <h1>成功!</h1> <!‐‐th:text 将div里面的文本内容设置为 ‐‐> <div th:text="${hello}">这是显示欢迎信息</div> </body> </html>
3.3, правила грамматики
1), th:text, изменить текстовое содержимое в текущем элементе;
th: любой html-атрибут, чтобы заменить значение нативного атрибута
2), выражение
Simple expressions:(表达式语法)
Variable Expressions: ${...}:获取变量值;OGNL;
1)、获取对象的属性、调用方法
2)、使用内置的基本对象:
#ctx : the context object.
#vars: the context variables.
#locale : the context locale.
#request : (only in Web Contexts) the HttpServletRequest object.
#response : (only in Web Contexts) the HttpServletResponse object.
#session : (only in Web Contexts) the HttpSession object.
#servletContext : (only in Web Contexts) the ServletContext object.
${session.foo}
3)、内置的一些工具对象:
#execInfo : information about the template being processed.
#messages : methods for obtaining externalized messages inside variables expressions, in the
same way as they would be obtained using #{…} syntax.
#uris : methods for escaping parts of URLs/URIs
#conversions : methods for executing the configured conversion service (if any).
#dates : methods for java.util.Date objects: formatting, component extraction, etc.
#calendars : analogous to #dates , but for java.util.Calendar objects.
#numbers : methods for formatting numeric objects.
#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
#objects : methods for objects in general.
#bools : methods for boolean evaluation.
#arrays : methods for arrays.
#lists : methods for lists.
#sets : methods for sets.
#maps : methods for maps.
#aggregates : methods for creating aggregates on arrays or collections.
#ids : methods for dealing with id attributes that might be repeated (for example, as a
result of an iteration).
Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样;
补充:配合 th:object="${session.user}:
<div th:object="${session.user}">
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
Message Expressions: #{...}:获取国际化内容
Link URL Expressions: @{...}:定义URL;
@{/order/process(execId=${execId},execType='FAST')}
Fragment Expressions: ~{...}:片段引用表达式
<div th:insert="~{commons :: main}">...</div>
Literals(字面量)
Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…
Text operations:(文本操作)
String concatenation: +
Literal substitutions: |The name is ${name}|
Arithmetic operations:(数学运算)
Binary operators: + , ‐ , * , / , %
4, автоматическая конфигурация SpringMVC
4.1 Автоконфигурация Spring MVC
Spring Boot автоматически настраивает SpringMVC
Ниже приведена конфигурация SpringBoot по умолчанию для SpringMVC: (Вебмвкаутоконфигуратион)
- Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
- ViewResolver настраивается автоматически (преобразователь представления: получить объект представления (View) в соответствии с возвращаемым значением метода, объект представления решает, как отображать (вперед? перенаправить?))
- ContentNegotiatingViewResolver: объединяет все преобразователи представлений;
- Как настроить: мы можем сами добавить в контейнер преобразователь представления, автоматически объединить его;
- Поддержка обслуживания статических ресурсов, включая поддержку WebJars (см. ниже).Путь к папке статических ресурсов, webjars
- Статическая поддержка index.html Доступ к статической домашней странице
- Custom Favicon support (see below). favicon.ico
- Автоматически зарегистрированы Converter , GenericConverter , Formatter bean-компоненты Converter: Converter public String hello(User user): Преобразование типов использует Converter Formatter formatter 2017.12.17===Date;
@Bean
@ConditionalOnProperty(prefix = "spring.mvc", name = "date‐format")//在文件中配置日期格
式化的规则
public Formatter<Date> dateFormatter() {
return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件
}
Конвертер форматтера добавили сами, нам нужно только поместить его в контейнер
- Support for HttpMessageConverters (see below).
- HttpMessageConverter: SpringMVC используется для преобразования запросов и ответов Http; Пользователь --- Json
- HttpMessageConverters определяются из контейнера, получаем все HttpMessageConverters, добавляем HttpMessageConverters в контейнер самостоятельно, просто регистрируем свои компоненты в контейнере (@Bean, @Component)
- Автоматическая регистрация MessageCodesResolver (см. ниже) Определение правил генерации кода ошибки
- Автоматическое использование bean-компонента ConfigurableWebBindingInitializer (см. ниже). Мы можем настроить ConfigurableWebBindingInitializer для замены значения по умолчанию (добавлено в контейнер).
4.2 Расширение SpringMVC
<mvc:view‐controller path="/hello" view‐name="success"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean></bean>
</mvc:interceptor>
</mvc:interceptors>
Напишите класс конфигурации (@Configuration), который имеет тип WebMvcConfigurerAdapter, не может быть помечен @EnableWebMvc;
Не только сохраняет всю автоматическую конфигурацию, но также может использовать нашу расширенную конфигурацию;
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /atguigu 请求来到 success
registry.addViewController("/atguigu").setViewName("success");
}
}
принцип:
1), WebMvcAutoConfiguration — это класс автоматической настройки SpringMVC.
2), он будет импортирован при выполнении других автоматических настроек; @Import(Енаблевебмвкконфигуратион.class)
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
//从容器中获取所有的WebMvcConfigurer
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
//一个参考实现;将所有的WebMvcConfigurer相关配置都来一起调用;
@Override
// public void addViewControllers(ViewControllerRegistry registry) {
// for (WebMvcConfigurer delegate : this.delegates) {
// delegate.addViewControllers(registry);
// }
}
}
}
3) Все WebMvcConfigurers в контейнере будут работать вместе;
4) также будет вызван наш класс конфигурации;
Эффект: автоматическая конфигурация SpringMVC и наша конфигурация расширения будут работать;
4.3 Полностью захватить SpringMVC;
SpringBoot не нуждается в автоматической настройке SpringMVC, все настраивается нами, вся автоматическая настройка SpringMVC недействительна, нам нужно добавить @EnableWebMvc в класс конфигурации;
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /atguigu 请求来到 success
registry.addViewController("/atguigu").setViewName("success");
}
}
принцип:
Почему автоконфигурация @EnableWebMvc не работает;
1) Ядро @EnableWebMvc
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
2),
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
3),
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
//容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
4) @EnableWebMvc импортирует компонент WebMvcConfigurationSupport;
5) Импортированная WebMvcConfigurationSupport — это только самая основная функция SpringMVC;
5. Как изменить конфигурацию SpringBoot по умолчанию
модель:
1) Когда SpringBoot автоматически настраивает множество компонентов, он в первую очередь смотрит, есть ли в контейнере настроенные пользователем (@Bean, @Component) Каждый (ViewResolver) сочетает в себе настроенные пользователем и свои дефолтные;
2), в SpringBoot будет много xxxConfigurers, которые помогут нам с расширенной настройкой.
3), в SpringBoot будет много xxxCustomizers, которые помогут нам настроить конфигурацию
6. RESTSY CRUD.
1), доступ по умолчанию к домашней странице
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
//@EnableWebMvc 不要接管SpringMVC
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /atguigu 请求来到 success
registry.addViewController("/atguigu").setViewName("success");
}
//所有的WebMvcConfigurerAdapter组件都会一起起作用
@Bean //将组件注册在容器
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
}
};
return adapter;
}
}
2) Интернационализация
- Написать файлы конфигурации интернационализации;
- Используйте ResourceBundleMessageSource для управления интернационализированными файлами ресурсов.
- Используйте fmt:message для извлечения интернационализированного контента на странице.
шаг:
а. Напишите файл конфигурации интернационализации и извлеките сообщения интернационализации, которые необходимо отображать на странице
б) SpringBoot автоматически настраивает компоненты для управления интернационализированными файлами ресурсов;
@ConfigurationProperties(prefix = "spring.messages")
public class MessageSourceAutoConfiguration {
/**
* Comma‐separated list of basenames (essentially a fully‐qualified classpath
* location), each following the ResourceBundle convention with relaxed support for
* slash based locations. If it doesn't contain a package qualifier (such as
* "org.mypackage"), it will be resolved from the classpath root.
*/
private String basename = "messages";
//我们的配置文件可以直接放在类路径下叫messages.properties;
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(this.basename)) {
//设置国际化资源文件的基础名(去掉语言国家代码的)
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(this.basename)));
}
if (this.encoding != null) {
messageSource.setDefaultEncoding(this.encoding.name());
}
messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
messageSource.setCacheSeconds(this.cacheSeconds);
messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
return messageSource;
}
@ConfigurationProperties(prefix = "spring.messages")
public class MessageSourceAutoConfiguration { 3
private String basename = "messages";
//我们的配置文件可以直接放在类路径下叫messages.properties; 12
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(this.basename)) {
//设置国际化资源文件的基础名(去掉语言国家代码的) messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(this.basename))); 20 }
if (this.encoding != null) {
messageSource.setDefaultEncoding(this.encoding.name()); 23 }
messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
messageSource.setCacheSeconds(this.cacheSeconds);
messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
return messageSource; 28 }
C. Перейдите на страницу, чтобы получить интернационализированное значение;
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http‐equiv="Content‐Type" content="text/html; charset=UTF‐8">
<meta name="viewport" content="width=device‐width, initial‐scale=1, shrink‐to‐
fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Signin Template for Bootstrap</title>
<!‐‐ Bootstrap core CSS ‐‐>
<link href="asserts/css/bootstrap.min.css"
th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
<!‐‐ Custom styles for this template ‐‐>
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}"
rel="stylesheet">
</head>
<body class="text‐center">
<form class="form‐signin" action="dashboard.html">
<img class="mb‐4" th:src="@{/asserts/img/bootstrap‐solid.svg}"
src="asserts/img/bootstrap‐solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb‐3 font‐weight‐normal" th:text="#{login.tip}">Please sign
in</h1>
<label class="sr‐only" th:text="#{login.username}">Username</label>
<input type="text" class="form‐control" placeholder="Username" th:placeholder="#
{login.username}" required="" autofocus="">
<label class="sr‐only" th:text="#{login.password}">Password</label>
<input type="password" class="form‐control" placeholder="Password"
th:placeholder="#{login.password}" required="">
<div class="checkbox mb‐3">
<label>
<input type="checkbox" value="remember‐me"/> [[#{login.remember}]]
</label>
</div>
<button class="btn btn‐lg btn‐primary btn‐block" type="submit" th:text="#
{login.btn}">Sign in</button>
<p class="mt‐5 mb‐3 text‐muted">© 2017‐2018</p>
<a class="btn btn‐sm">中文</a>
<a class="btn btn‐sm">English</a>
</form>
</body>
</html>
Эффект: интернационализация переключается в соответствии с информацией, установленной языком браузера;
принцип:
Интернационализированный Locale (региональный информационный объект); LocaleResolver (получает региональный информационный объект); по умолчанию используется Locale в соответствии с региональной информацией, полученной в заголовке запроса для интернационализации
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties
.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
г. Нажмите на ссылку, чтобы переключить интернационализацию
/**
* 可以在连接上携带区域信息
*/
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String l = request.getParameter("l");
Locale locale = Locale.getDefault();
if(!StringUtils.isEmpty(l)){
String[] split = l.split("_");
locale = new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale
locale) {
}
}
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}
3), войти
После того, как страница механизма шаблонов будет изменена во время разработки, она вступит в силу в режиме реального времени.
а. Отключите кеш механизма шаблонов
# 禁用缓存
spring.thymeleaf.cache=false
б) после завершения модификации страницы, ctrl+f9: перекомпилировать, отображение сообщения об ошибке входа
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
4), перехватчик выполняет проверку входа
перехватчик
/**
* 登陆检查,
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
//目标方法执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
if(user == null){
//未登陆,返回登陆页面
request.setAttribute("msg","没有权限请先登陆");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{
//已登陆,放行请求
return true;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object
handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
}
зарегистрировать перехватчик
//所有的WebMvcConfigurerAdapter组件都会一起起作用
@Bean //将组件注册在容器
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
registry.addViewController("/main.html").setViewName("dashboard");
}
//注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//super.addInterceptors(registry);
//静态资源; *.css , *.js
//SpringBoot已经做好了静态资源映射
registry.addInterceptor(new
LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login");
}
};
return adapter;
}
5), CRUD-список сотрудников
Экспериментальные требования:
А. RestfulCRUD: CRUD соответствует стилю Rest;
URI: /имя ресурса/идентификатор ресурса. Метод HTTP-запроса различает операции CRUD над ресурсами.
обычныйCRUD(uriразличать операции) | RestfulCRUD | |
---|---|---|
Запрос | getEmp | emp---GET |
Добавить к | addEmp?xxx | emp---POST |
Исправлять | updateEmp?id=xxx&xxx=xx | emp/{id}---PUT |
Удалить | deleteEmp?id=1 | emp/{id}---DELETE |
б) структура запроса эксперимента;
Экспериментальные функции | проситьURI | метод запроса |
---|---|---|
Опрос всех сотрудников | emps | GET |
Запросить сотрудника (перейти на страницу модификации) | emp/1 | GET |
перейти к добавлению страницы | emp | GET |
Добавить сотрудников | emp | POST |
Перейти на страницу модификации (узнать у сотрудника для информации эхо) | emp/1 | GET |
изменить сотрудника | emp | PUT |
удалить сотрудника | emp/1 | DELETE |
в. Список сотрудников:
thymeleafИзвлечение общих элементов страницы
1、抽取公共片段
<div th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</div>
2、引入公共片段
<div th:insert="~{footer :: copy}"></div>
~{templatename::selector}:模板名::选择器
~{templatename::fragmentname}:模板名::片段名
3、默认效果:
insert的公共片段在div标签中
如果使用th:insert等属性进行引入,可以不用写~{}:
行内写法可以加上:[[~{}]];[(~{})];
Есть три атрибута, которые вводят общие фрагменты:
th:insert: вставляет общедоступный фрагмент целиком в элемент, введенный объявлением
th:replace: заменить элемент, введенный объявлением, на публичный фрагмент
th:include: включить в этот тег содержимое импортированного фрагмента.
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</footer>
引入方式
<div th:insert="footer :: copy"></div>
引入片段的时候传入参数:
6)、CRUD-员工添加
添加页面
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
效果
<div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
</div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
<div>
© 2011 The Good Thymes Virtual Grocery
</div>
7. Механизм обработки ошибок
1), механизм обработки ошибок SpringBoot по умолчанию
Эффект по умолчанию:
а, браузер возвращает страницу ошибки по умолчанию
б. Если это другой клиент, он по умолчанию отвечает данными в формате JSON.
принцип:
Вы можете обратиться к ErrorMvcAutoConfiguration; автоматическая настройка обработки ошибок; добавлены следующие компоненты в контейнер
-
DefaultErrorAttributes: Помогите нам поделиться информацией на странице;
@Override public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>(); errorAttributes.put("timestamp", new Date()); addStatus(errorAttributes, requestAttributes); addErrorDetails(errorAttributes, requestAttributes, includeStackTrace); addPath(errorAttributes, requestAttributes); return errorAttributes; }
-
BasicErrorController: обрабатывает запросы по умолчанию/ошибки
@Controller @RequestMapping("${server.error.path:${error.path:/error}}") public class BasicErrorController extends AbstractErrorController { @RequestMapping(produces = "text/html")//产生html类型的数据;浏览器发送的请求来到这个方法处理 public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes( request, isIncludeStackTrace(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); //去哪个页面作为错误页面;包含页面地址和页面内容 ModelAndView modelAndView = resolveErrorView(request, response, status, model); return (modelAndView == null ? new ModelAndView("error", model) : modelAndView); } @RequestMapping @ResponseBody //产生json数据,其他客户端来到这个方法处理; public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = getStatus(request); return new ResponseEntity<Map<String, Object>>(body, status); }
-
ErrorPageCustomizer:
@Value("${error.path:/error}") //系统出现错误以后来到error请求进行处理;(web.xml注册的错误页面规则) private String path = "/error";
-
Дефаултеррорвиевресолвер:
@Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) { ModelAndView modelAndView = resolve(String.valueOf(status), model); if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) { modelAndView = resolve(SERIES_VIEWS.get(status.series()), model); } return modelAndView; } private ModelAndView resolve(String viewName, Map<String, Object> model) { //默认SpringBoot可以去找到一个页面? error/404 String errorViewName = "error/" + viewName; //模板引擎可以解析这个页面地址就用模板引擎解析 TemplateAvailabilityProvider provider = this.templateAvailabilityProviders .getProvider(errorViewName, this.applicationContext); if (provider != null) { //模板引擎可用的情况下返回到errorViewName指定的视图地址 return new ModelAndView(errorViewName, model); } //模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面 error/404.html return resolveResource(errorViewName, model); }
шаг:
Как только в системе возникнет ошибка типа 4xx или 5xx, вступит в силу ErrorPageCustomizer (настраиваемые правила ответа на ошибку), придет на запрос /error, будетBasicErrorControllerиметь дело с;
-
страница ответа; на какую страницу перейти, определяетсяDefaultErrorViewResolverпроанализировано;
protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) { //所有的ErrorViewResolver得到ModelAndView for (ErrorViewResolver resolver : this.errorViewResolvers) { ModelAndView modelAndView = resolver.resolveErrorView(request, status, model); if (modelAndView != null) { return modelAndView; } } return null; }
2), как настроить реакцию на ошибку:
А. Как настроить не ту страницу;
-
В случае шаблонизатора;error/код состояния;[Назовите страницу ошибки как error status code.html и поместите ее в папку error в папке движка шаблона], ошибка с этим кодом статуса придет на соответствующую страницу;
Мы можем использовать 4xx и 5xx в качестве имени файла страницы ошибки, чтобы сопоставить все ошибки этого типа, сначала точные (предпочтительно найти точный код состояния.html);
Информация, которую может получить страница:timestamp:
- отметка времени
- статус: код состояния
- ошибка: исключение подсказки об ошибке: объект исключения
- сообщение: сообщение об исключении
- ошибки: все ошибки проверки данных JSR303 здесь
-
Механизма шаблонов нет (движок шаблонов не может найти эту страницу с ошибкой), посмотрите в папке статических ресурсов;
-
Выше нет страницы ошибок, то есть страница сообщений об ошибках SpringBoot по умолчанию появляется по умолчанию;
б. Как настроить неправильныйjsonданные;
-
Пользовательская обработка исключений и возврат пользовательских данных json;
@ControllerAdvice public class MyExceptionHandler { @ResponseBody @ExceptionHandler(UserNotExistException.class) public Map<String,Object> handleException(Exception e){ Map<String,Object> map = new HashMap<>(); map.put("code","user.notexist"); map.put("message",e.getMessage()); return map; } } //没有自适应效果...
-
Переслать в /error для обработки эффекта адаптивного ответа
@ExceptionHandler(UserNotExistException.class) public String handleException(Exception e, HttpServletRequest request){ Map<String,Object> map = new HashMap<>(); //传入我们自己的错误状态码 4xx 5xx,否则就不会进入定制错误页面的解析流程 /** * Integer statusCode = (Integer) request .getAttribute("javax.servlet.error.status_code"); */ request.setAttribute("javax.servlet.error.status_code",500); map.put("code","user.notexist"); map.put("message",e.getMessage()); //转发到/error return "forward:/error"; }
3), выполнить наши индивидуальные данные;
После возникновения ошибки ей придет запрос /error, который будет обработан BasicErrorController, а данные, которые можно получить в ответ, — это
GetErrorAttributes (метод, заданный AbstractErrorController (ErrorController));
-
Полностью напишите класс реализации ErrorController [или напишите подкласс AbstractErrorController] и поместите его в контейнер;
-
Данные, которые могут быть использованы на странице, или данные, которые могут быть возвращены json, получаются через errorAttributes.getErrorAttributes, DefaultErrorAttributes.getErrorAttributes() в контейнере, обработка данных выполняется по умолчанию;
Пользовательские атрибуты ошибок
//给容器中加入我们自己定义的ErrorAttributes @Component public class MyErrorAttributes extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace); map.put("company","atguigu"); return map; }
Конечный результат: ответ является адаптивным, а возвращаемый контент можно изменить, настроив ErrorAttributes,
8, настроить встроенныйServletконтейнер
SpringBoot по умолчанию использует Tomcat в качестве встроенного контейнера сервлетов;
1), как настроить и изменитьServletСвязанная конфигурация контейнера;
-
Измените конфигурацию, связанную с сервером (ServerProperties [также EmbeddedServletContainerCustomizer]);
server.port=8081 server.context‐path=/crud server.tomcat.uri‐encoding=UTF‐8 //通用的Servlet容器设置 server.xxx //Tomcat的设置 server.tomcat.xxx
-
написатьEmbeddedServletContainerCustomizer: Настройщик встроенного контейнера сервлетов; для изменения конфигурации контейнера сервлетов
@Bean //一定要将这个定制器加入到容器中 public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){ return new EmbeddedServletContainerCustomizer() { //定制嵌入式的Servlet容器相关的规则 @Override public void customize(ConfigurableEmbeddedServletContainer container) { container.setPort(8083); } }; }
2), зарегистрируйте три основных компонента сервлета [Servlet, Filter, Listener]
Поскольку SpringBoot по умолчанию запускает встроенный контейнер сервлетов в виде пакета jar для запуска веб-приложения SpringBoot, файл web.xml отсутствует.
Зарегистрируйте три компонента следующими способами
ServletRegistrationBean
//注册三大组件
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new
MyServlet(),"/myServlet");
return registrationBean;
}
FilterRegistrationBean
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
return registrationBean;
}
ServletListenerRegistrationBean
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new
ServletListenerRegistrationBean<>(new MyListener());
return registrationBean;
}
Когда SpringBoot автоматически настраивает SpringMVC для нас, он автоматически регистрирует интерфейсный контроллер SpringMVC: DISpatcherServlet;
DispatcherServletAutoConfigurationсередина:
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name =
DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public ServletRegistrationBean dispatcherServletRegistration(
DispatcherServlet dispatcherServlet) {
ServletRegistrationBean registration = new ServletRegistrationBean(
dispatcherServlet, this.serverProperties.getServletMapping());
//默认拦截: / 所有请求;包静态资源,但是不拦截jsp请求; /*会拦截jsp
//可以通过server.servletPath来修改SpringMVC前端控制器默认拦截的请求路径
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(
this.webMvcProperties.getServlet().getLoadOnStartup());
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
return registration;
}
3), заменить на другие встроенныеServletконтейнер
Поддержка по умолчанию:
Tomcat (используется по умолчанию)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
引入web模块默认就是使用嵌入式的Tomcat作为Servlet容器;
</dependency>
Jetty
<!‐‐ 引入web模块 ‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring‐boot‐starter‐tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!‐‐引入其他的Servlet容器‐‐>
<dependency>
<artifactId>spring‐boot‐starter‐jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
Undertow
<!‐‐ 引入web模块 ‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring‐boot‐starter‐tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!‐‐引入其他的Servlet容器‐‐>
<dependency>
<artifactId>spring‐boot‐starter‐undertow</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
4), принцип автоматической настройки встроенного контейнера сервлетов;
EmbeddedServletContainerAutoConfiguration: Автоконфигурация встроенного контейнера сервлетов?
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//导入BeanPostProcessorsRegistrar:Spring注解版;给容器中导入一些组件
//导入了EmbeddedServletContainerCustomizerBeanPostProcessor:
//后置处理器:bean初始化前后(创建完对象,还没赋值赋值)执行初始化工作
public class EmbeddedServletContainerAutoConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })//判断当前是否引入了Tomcat依赖;
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search =
SearchStrategy.CURRENT)//判断当前容器没有用户自己定义EmbeddedServletContainerFactory:嵌入式的
Servlet容器工厂;作用:创建嵌入式的Servlet容器
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory()
{
return new TomcatEmbeddedServletContainerFactory();
}
}
/**
* Nested configuration if Jetty is being used.
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
WebAppContext.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search =
SearchStrategy.CURRENT)
public static class EmbeddedJetty {
@Bean
public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
return new JettyEmbeddedServletContainerFactory();
}
}
/**
* Nested configuration if Undertow is being used.
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search =
SearchStrategy.CURRENT)
public static class EmbeddedUndertow {
@Bean
public UndertowEmbeddedServletContainerFactory
undertowEmbeddedServletContainerFactory() {
return new UndertowEmbeddedServletContainerFactory();
}
}
-
EmbeddedServletContainerFactory (Фабрика встроенных контейнеров сервлетов)
public interface EmbeddedServletContainerFactory { //获取嵌入式的Servlet容器 EmbeddedServletContainer getEmbeddedServletContainer( ServletContextInitializer... initializers); }
-
EmbeddedServletContainer: (встроенный контейнер сервлетов)
-
отTomcatEmbeddedServletContainerFactoryНапример
@Override public EmbeddedServletContainer getEmbeddedServletContainer( ServletContextInitializer... initializers) { //创建一个Tomcat Tomcat tomcat = new Tomcat(); //配置Tomcat的基本环节 File baseDir = (this.baseDirectory != null ? this.baseDirectory : createTempDir("tomcat")); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); tomcat.getService().addConnector(connector); customizeConnector(connector); tomcat.setConnector(connector); tomcat.getHost().setAutoDeploy(false); configureEngine(tomcat.getEngine()); for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } prepareContext(tomcat.getHost(), initializers); //将配置好的Tomcat传入进去,返回一个EmbeddedServletContainer;并且启动Tomcat服务器 return getTomcatEmbeddedServletContainer(tomcat);
Как вступают в силу наши изменения конфигурации встроенного контейнера?
ServerProperties、EmbeddedServletContainerCustomizer
EmbeddedServletContainerCustomizer: Настройщик помог нам изменить конфигурацию контейнера сервлетов? Как изменить принцип?
EmbeddedServletContainerCustomizerBeanPostProcessor импортируется в контейнер
//初始化之前 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { //如果当前初始化的是一个ConfigurableEmbeddedServletContainer类型的组件 if (bean instanceof ConfigurableEmbeddedServletContainer) { // postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean); } return bean; } private void postProcessBeforeInitialization( ConfigurableEmbeddedServletContainer bean) { //获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值; for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) { customizer.customize(bean); } } private Collection<EmbeddedServletContainerCustomizer> getCustomizers() { if (this.customizers == null) { // Look up does not include the parent context this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>( this.beanFactory //从容器中获取所有这葛类型的组件:EmbeddedServletContainerCustomizer //定制Servlet容器,给容器中可以添加一个EmbeddedServletContainerCustomizer类型的组件 .getBeansOfType(EmbeddedServletContainerCustomizer.class, false, false) .values()); Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE); this.customizers = Collections.unmodifiableList(this.customizers); } return this.customizers; } ServerProperties也是定制器
шаг:
А. SpringBoot добавляет в контейнер соответствующие зависимости в соответствии с импортированными зависимостями.
EmbeddedServletContainerFactory [TomcatEmbeddedServletContainerFactory]
б) Если компонент в контейнере хочет создать объект, постпроцессор будет предупрежден: EmbeddedServletContainerCustomizerBeanPostProcessor;
Пока это встроенная фабрика контейнеров сервлетов, постпроцессор будет работать;
c, постпроцессор, получить всеEmbeddedServletContainerCustomizer, который вызывает пользовательский метод настройщика
5) встроенный принцип запуска контейнера сервлетов;
Когда создавать встроенную фабрику контейнеров сервлетов?
Когда получить контейнер встроенных сервлетов и запустить Tomcat; получить фабрику контейнеров встроенных сервлетов:
-
Приложение SpringBoot запускается и запускает метод run
-
refreshContext(context); SpringBoot обновляет контейнер IOC [создает объект-контейнер IOC, инициализирует контейнер и создает каждый компонент в контейнере]; если это создание веб-приложенияAnnotationConfigEmbeddedWebApplicationContext, в противном случае:AnnotationConfigApplicationContext
-
обновить (контекст); обновить только что созданныйiocконтейнер;
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post‐processing of the bean factory in context subclasses.
-
onRefresh(); веб-контейнер ioc переопределяет метод onRefresh
-
Контейнер webioc создаст встроенный контейнер сервлета;createEmbeddedServletContainer();
-
внедрятьсяServletКонтейнерный завод:
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
Получите компонент EmbeddedServletContainerFactory из контейнера ioc;TomcatEmbeddedServletContainerFactoryСоздайте объект.Как только постпроцессор увидит этот объект, он получит все настройщики для настройки соответствующей конфигурации контейнера сервлетов в первую очередь;
-
Используйте фабрику контейнеров для встраиванияServletконтейнер:
this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer());
-
Встроенный контейнер сервлета создает объект и запускает контейнер сервлета;
Запустить встроенныйServletконтейнер, затемiocПолучены оставшиеся несозданные объекты в контейнере;
IOCзапуск контейнера создает встроенныйServletконтейнер
9. Используйте внешний контейнер сервлета
9.1. Встроенный контейнер сервлетов:
Приложение упаковано в исполняемый jar
Преимущества: простой, портативный;
Недостатки: JSP не поддерживается по умолчанию, а оптимизация и настройка усложняются (с помощью настройщика [ServerProperties, custom
EmbeddedServletContainerCustomizer], самостоятельно напишите фабрику создания встроенного контейнера сервлетов
[Фабрика встроенных контейнеров сервлетов]);
9.2 Внешние контейнеры сервлетов
Установите Tomcat снаружи --- пакет, применив военный пакет;
шаг
-
Должен быть создан военный проект; (используйте идею для создания структуры каталогов)
-
Укажите встроенный Tomcat, как указано;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter‐tomcat</artifactId> <scope>provided</scope> </dependency>
-
должен написатьSpringBootServletInitializerподкласс и вызовите метод configure
public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { //传入SpringBoot应用的主程序 return application.sources(SpringBoot04WebJspApplication.class); } }
-
Запустите сервер, и вы можете использовать его;
9.3 Принцип
-
пакет jar: выполнить основной метод основного класса SpringBoot -> запустить контейнер ioc -> создать контейнер встроенного сервлета;
-
Пакет WAR: Запустите сервер -> запуск сервераSpringBootПрименить [SpringBootServletInitializer] -> запустить контейнер ioc;
servlet3.0 (весенняя версия аннотации):
Возможность подключения общих библиотек/сред выполнения: Правила:
-
Запуск сервера (запуск веб-приложения) создаст экземпляр ServletContainerInitializer в каждом пакете jar в текущем веб-приложении:
-
Реализация ServletContainerInitializer помещается в папку META-INF/services пакета jar, и есть файл с именем
Файл javax.servlet.ServletContainerInitializer, содержимое которого представляет собой полное имя класса класса реализации ServletContainerInitializer.
-
Мы также можем использовать @HandlesTypes для загрузки интересующих нас классов при запуске приложения;
Процесс:
-
запустить Томкэт
-
org\springframework\spring-web\4.3.14.RELEASE\spring-web-4.3.14.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer:
В веб-модуле Spring есть этот файл:org.springframework.web.SpringServletContainerInitializer
-
SpringServletContainerInitializer передает все классы этого типа, помеченные @HandlesTypes(WebApplicationInitializer.class), в Set> метода onStartup, создает экземпляры для этих классов типа WebApplicationInitializer;
-
Каждый WebApplicationInitializer вызывает свой onStartup;
-
Будет создан класс, эквивалентный нашему SpringBootServletInitializer, и будет выполнен метод onStartup.
-
Когда экземпляр SpringBootServletInitializer выполняется при запуске, он создастRootApplicationContext; создаст контейнер
protected WebApplicationContext createRootApplicationContext( ServletContext servletContext) { //1、创建SpringApplicationBuilder SpringApplicationBuilder builder = createSpringApplicationBuilder(); StandardServletEnvironment environment = new StandardServletEnvironment(); environment.initPropertySources(servletContext, null); builder.environment(environment); builder.main(getClass()); ApplicationContext parent = getExistingRootWebApplicationContext(servletContext); if (parent != null) { this.logger.info("Root context already created (using as parent)."); servletContext.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null); builder.initializers(new ParentContextApplicationContextInitializer(parent)); } builder.initializers( new ServletContextApplicationContextInitializer(servletContext)); builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class); //调用configure方法,子类重写了这个方法,将SpringBoot的主程序类传入了进来 builder = configure(builder); //使用builder创建一个Spring应用 SpringApplication application = builder.build(); if (application.getSources().isEmpty() && AnnotationUtils .findAnnotation(getClass(), Configuration.class) != null) { application.getSources().add(getClass()); } Assert.state(!application.getSources().isEmpty(), "No SpringApplication sources have been defined. Either override the " + "configure method or add an @Configuration annotation"); // Ensure error pages are registered if (this.registerErrorPageFilter) { application.getSources().add(ErrorPageFilterConfiguration.class); } //启动Spring应用 return run(application); }
-
Запускается приложение Spring и создается контейнер IOC.
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); Banner printedBanner = printBanner(environment); context = createApplicationContext(); analyzers = new FailureAnalyzers(context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); //刷新IOC容器 refreshContext(context); afterRefresh(context, applicationArguments); listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }
запускатьServletконтейнер, перезапуститьSpringBootприменение
Пять, SpringBoot и доступ к данным
1, JDBC
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql‐connector‐java</artifactId>
<scope>runtime</scope>
</dependency>
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://192.168.15.22:3306/jdbc
driver‐class‐name: com.mysql.jdbc.Driver
По умолчанию в качестве источника данных используется org.apache.tomcat.jdbc.pool.DataSource;
Соответствующая конфигурация источника данных находится в DataSourceProperties;
Принцип автоматической настройки:
org.springframework.boot.autoconfigure.jdbc:
-
Обратитесь к DataSourceConfiguration, создайте источник данных в соответствии с конфигурацией и используйте пул соединений Tomcat по умолчанию; вы можете использовать
Spring.DataSource.Type Задает пользовательский тип источника данных;
-
SpringBoot может поддерживать его по умолчанию;
org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource、
-
Пользовательский тип источника данных
/** * Generic DataSource configuration. */ @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type") static class Generic { @Bean public DataSource dataSource(DataSourceProperties properties) { //使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性 return properties.initializeDataSourceBuilder().build(); } }
-
DataSourceInitializer:ApplicationListener;
эффект:
-
runSchemaScripts(); запустить оператор построения таблицы;
-
runDataScripts(); запустить оператор SQL, который вставляет данные;
По умолчанию просто назовите файл как:
schema‐*.sql、data‐*.sql
默认规则:schema.sql,schema‐all.sql;
可以使用
schema:
‐ classpath:department.sql
指定位置
- Операционная база данных: Операционная база данных JdbcTemplate настраивается автоматически.
2, Интеграция источников данных Druid
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
//配置Druid的监控
//1、配置一个管理后台的Servlet
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(),
"/druid/*");
Map<String,String> initParams = new HashMap<>();
initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
initParams.put("allow","");//默认就是允许所有访问
initParams.put("deny","192.168.15.21");
bean.setInitParameters(initParams);
return bean;
}
//2、配置一个web监控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}
3, интеграцияMyBatis
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis‐spring‐boot‐starter</artifactId>
<version>1.3.1</version>
</dependency>
шаг:
-
Настройка свойств, связанных с источником данных
-
Создайте таблицу для базы данных
-
Создать JavaBean
-
Аннотированная версия
//指定这是一个操作数据库的mapper @Mapper public interface DepartmentMapper { @Select("select * from department where id=#{id}") public Department getDeptById(Integer id); @Delete("delete from department where id=#{id}") public int deleteDeptById(Integer id); @Options(useGeneratedKeys = true,keyProperty = "id") @Insert("insert into department(departmentName) values(#{departmentName})") public int insertDept(Department department); @Update("update department set departmentName=#{departmentName} where id=#{id}") public int updateDept(Department department); }
проблема:
Настройте правила конфигурации MyBatis, добавьте в контейнер ConfigurationCustomizer;
@org.springframework.context.annotation.Configuration public class MyBatisConfig { @Bean public ConfigurationCustomizer configurationCustomizer(){ return new ConfigurationCustomizer(){ @Override public void customize(Configuration configuration) { configuration.setMapUnderscoreToCamelCase(true); } }; } }
使用MapperScan批量扫描所有的Mapper接口; @MapperScan(value = "com.atguigu.springboot.mapper") @SpringBootApplication public class SpringBoot06DataMybatisApplication { public static void main(String[] args) { SpringApplication.run(SpringBoot06DataMybatisApplication.class, args); } }
-
Версия профиля
mybatis: config‐location: classpath:mybatis/mybatis‐config.xml 指定全局配置文件的位置 mapper‐locations: classpath:mybatis/mapper/*.xml 指定sql映射文件的位置
4. Интеграция SpringData JPA
-
Напишите класс сущности (компонент) для сопоставления с таблицей данных и настройте отношение сопоставления;
//使用JPA注解配置映射关系 @Entity //告诉JPA这是一个实体类(和数据表映射的类) @Table(name = "tbl_user") //@Table来指定和哪个数据表对应;如果省略默认表名就是user; public class User { @Id //这是一个主键 @GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键 private Integer id; @Column(name = "last_name",length = 50) //这是和数据表对应的一个列 private String lastName; @Column //省略默认列名就是属性名 private String email;
-
Напишите интерфейс Dao для работы с таблицей данных (репозиторий), соответствующей классу сущности.
//继承JpaRepository来完成对数据库的操作 public interface UserRepository extends JpaRepository<User,Integer> { }
-
Базовая конфигурация JpaProperties
spring: jpa: hibernate: # 更新或者创建数据表结构 ddl‐auto: update # 控制台显示SQL show‐sql: true
6. Принцип стартовой конфигурации
Несколько важных механизмов обратного вызова событий
Настроено в META-INF/spring.factories
ApplicationContextInitializer
SpringApplicationRunListener
Просто нужно положить в контейнер iocApplicationRunner CommandLineRunner
Запустите процесс:
1,СоздайтеSpringApplicationобъект
initialize(sources);
private void initialize(Object[] sources) {
//保存主配置类
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//判断当前是否一个web应用
this.webEnvironment = deduceWebEnvironment();
//从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起
来
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//从类路径下找到ETA‐INF/spring.factories配置的所有ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
2,бегатьrunметод
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
//获取SpringApplicationRunListeners;从类路径下META‐INF/spring.factories
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的获取SpringApplicationRunListener.starting()方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准
备完成
Banner printedBanner = printBanner(environment);
//创建ApplicationContext;决定创建web的ioc还是普通的ioc
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
//准备上下文环境;将environment保存到ioc中;而且applyInitializers();
//applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
//回调所有的SpringApplicationRunListener的contextPrepared();
//
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
//s刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版
//扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
refreshContext(context);
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
//ApplicationRunner先回调,CommandLineRunner再回调
afterRefresh(context, applicationArguments);
//所有的SpringApplicationRunListener回调finished方法
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//整个SpringBoot应用启动完成以后返回启动的ioc容器;
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
3, механизм мониторинга событий
Настроено в META-INF/spring.factoriesApplicationContextInitializer
public class HelloApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("ApplicationContextInitializer...initialize..."+applicationContext);
}
}
SpringApplicationRunListener
Конфигурация (META-INF/spring.factories)
org.springframework.context.ApplicationContextInitializer=\
com.atguigu.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.atguigu.springboot.listener.HelloSpringApplicationRunListener
Просто нужно положить в контейнер ioc
ApplicationRunner
@Component
public class HelloApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner...run....");
}
}
CommandLineRunner
@Component
public class HelloCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));
}
}
Примечание источник:
Официальная документация SpringBoot
"Видеозаметки Шан Силиконовой долины"