Привет всем, я Сяофу~
из конфигурациидокументсерединаполучать Свойства должныдаSpringBoot
развиватьсередина Одна из наиболее часто используемых функций.,Но для такой часто используемой функции, как да,До сих пор существует немало застройщиков, которые попадают в эту ловушку.
я разобрался с несколькимиполучать Как настроить свойства,Цель состоит не только в том, чтобы каждый мог научиться.,более важныйдаПонимание основных принципов загрузки и чтения конфигурации.,При возникновении проблемы можно проанализировать ее первопричину.,Вместо этого выдается сообщение об ошибке, и атрибуты невозможно получить.,Проект безголового перезапуска,существовать ПредложенияБлинсередина Постепенно схожу с ума~
Все версии Springboot следующих примеров исходных кодов — 2.7.6.
Давайте рассмотрим эти игровые процессы и принципы один за другим, чтобы увидеть, какие из них вы раньше не использовали! Без лишних слов, давайте начнем~
использовать Environment способполучать Настроить значения свойств очень просто,Просто введитеEnvironmentкласс вызывает свой методgetProperty (ключ атрибута)
Вот и все,Но знай это, знай, почему это так.,Кратко разберемся в его принципе,Поскольку следующие несколькополучать Методы настройки:иэто тесно связано。
@Slf4j
@SpringBootTest
public class EnvironmentTest {
@Resource
private Environment env;
@Test
public void var1Test() {
String var1 = env.getProperty("env101.var1");
log.info("Environment Получение конфигурации {}", var1);
}
}
Среда — это основной интерфейс настройки среды Springboot. Он обеспечивает простой способ доступа к свойствам приложения, включая свойства системы, переменные среды операционной системы, параметры командной строки, свойства, определенные в файлах конфигурации приложения и т. д.
Процесс запуска программы Springboot,ВыполнюSpringApplication.run
серединаизprepareEnvironment()
Метод инициализации конфигурации,Итак, что же делается на каждом этапе процесса инициализации?
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
/**
* 1、создавать ConfigurableEnvironment Объект: первый звонок getOrCreateEnvironment() Как получить илисоздавать
* ConfigurableEnvironment Объект, хранящий параметры среды. Если вы уже сохранили существование ConfigurableEnvironment Object, затем напрямую использовать его; в противном случае создайте новый в соответствии с конфигурацией пользователя и конфигурацией по умолчанию.
*/
ConfigurableEnvironment environment = getOrCreateEnvironment();
/**
* 2. Разберите и проанализируйте указанный пользователем документ конфигурации, Воля как PropertySource Добавить к объекту средасередина Этот метод будет анализировать по умолчанию. application.properties и application.yml документ, и Воля его добавил в ConfigurableEnvironment объектсередина. * PropertySource или PropertySourcesPlaceholderConfigurer Индивидуальная настройка приложения нагрузки.
*/
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 3. Загрузите все свойства системы и добавьте их в ConfigurableEnvironment в объекте
ConfigurationPropertySources.attach(environment);
// 4. Сообщите слушателю, что параметры среды готовы.
listeners.environmentPrepared(bootstrapContext, environment);
/**
* 5. Все значения атрибутов в источнике атрибутов по умолчанию Воля перенесены в объект. конец очереди на среду,
Таким образом, определяемые пользователем значения атрибутов могут переопределять значения атрибутов по умолчанию. Это сделано для того, чтобы пользователи не могли случайно перезаписать Spring Boot Предоставлены свойства по умолчанию.
*/
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
// 6、Воля Spring Boot Свойства приложения привязаны кобъект среде, чтобы иметь возможность правильно читать ииспользовать эти свойства конфигурации
bindToSpringApplication(environment);
// 7. Если нет пользовательского типа среды, то используйте EnvironmentConverter Тип Воляобъект среда преобразуется в стандартный тип среды и добавляется в ConfigurableEnvironment объектсередина. if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
// 8. Настройте систему еще раз, чтобы предотвратить ее перезапись другими конфигурациями.
ConfigurationPropertySources.attach(environment);
return environment;
}
Взгляните на этапы процесса загрузки конфигурации:
ConfigurableEnvironment
Используется для хранения параметров среды;configureEnvironment
Метод загружает значение по умолчанию application.properties
и application.yml
файл конфигурации и файл конфигурации, указанный пользователем, который инкапсулирован как; PropertySource Добавить к объекту средысередина;attach()
: загрузить все свойства системы,и Воляони Добавить к объекту средысередина;listeners.environmentPrepared()
: Отправьте уведомление о прослушивании о том, что конфигурация параметров среды готова;moveToEnd()
: Воля Система по умолчанию Все значения атрибутов в источнике атрибутов перемещаются в объект конец очереди на среду,Таким образом, определяемые пользователем значения атрибутов могут переопределять значения атрибутов по умолчанию.bindToSpringApplication
: Свойства приложения привязаны к Bean на объекте;attach()
: Загрузите конфигурацию системы еще раз, чтобы предотвратить ее перезапись другими конфигурациями;В процессе загрузки конфигурации, описанном выше, различные атрибуты конфигурации будут инкапсулированы в абстрактные структуры данных. PropertySource
середина,Формат кода этой структуры данных следующий:,форма ключ-значение.
public abstract class PropertySource<T> {
protected final String name; // Имя источника свойства
protected final T source; // Исходное значение свойства (обобщенный тип, например Карта, Свойство)
public String getName(); // Получить имя источника атрибута
public T getSource(); // Получить исходное значение атрибута
public boolean containsProperty(String name); //Содержит ли да определенный атрибут
public abstract Object getProperty(String name); //Получаем значение атрибута, соответствующее имени атрибута
}
PropertySource
Существует ряд классов реализации, используемых для управления свойствами конфигурации приложения. другой PropertySource Классы реализации могут получать свойства конфигурации из разных источников, таких как файлы, переменные среды, параметры командной строки и т. д. Некоторые из задействованных классов реализации:
MapPropertySource
: Map Объект пар ключ-значение преобразуется в PropertySource Адаптер для предметов;PropertiesPropertySource
: Properties Все свойства конфигурации в объекте преобразуются в Spring Значения атрибутов в среде;ResourcePropertySource
: Из документа СИСТЕМА или classpath Загрузите свойства конфигурации и инкапсулируйте их в Объект PropertySource;ServletConfigPropertySource
: Servlet Прочитайте атрибуты конфигурации в конфигурации и инкапсулируйте их в PropertySource объект;ServletContextPropertySource
: Servlet Прочитайте свойства конфигурации в контексте и инкапсулируйте их в PropertySource объект;StubPropertySource
: Это пустой класс реализации, его функция заключается только в предоставлении CompositePropertySource Класс как источник родительского свойства по умолчанию, чтобы избежать исключений нулевого указателя;CompositePropertySource
: Это составной класс реализации, который поддерживается внутри компании. Очередь сбора PropertySource, их может быть несколько. PropertySource объединение объектов;SystemEnvironmentPropertySource
: Считайте свойства конфигурации из переменных среды операционной системы и инкапсулируйте их в PropertySource объект;Объекты PropertySource, созданные в результате вышеупомянутых различных инициализаций конфигурации, будут храниться в очереди сбора.
List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>()
Инициализация конфигурации завершена,контекст приложенияAbstractApplicationContext
встречанагрузка Конфигурация,Эта процедурасуществовать Вы можете запустить его в любое времяполучать Информация о конфигурации。
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// Контекст приложениянагрузкаобъекта среды
context.setEnvironment(environment);
postProcessApplicationContext(context);
.........
}
Разберитесь с процессом настройки нагрузки выше.,На самом деле, это легко понять, прочитав конфигурацию.,Не что иное, какда Пройти очередьPropertySource
,получить имя атрибутаname
Соответствует соответствующему значению атрибутаsource
。
PropertyResolver
даполучать Конфигурацияиз关键добрый,Внутри он обеспечивает операцииPropertySource
Методы очереди,основной методgetProperty(key)
получать Конфигурацияценить,Взгляните на зависимости этого класса,Обнаружить Environment
Это подкатегория.
Тогда действительно можно напрямую использовать PropertyResolver для получения свойств конфигурации. На данный момент у нас есть примерное представление о загрузке и чтении конфигурации Springboot.
@Slf4j
@SpringBootTest
public class EnvironmentTest {
@Resource
private PropertyResolver env;
@Test
public void var1Test() {
String var1 = env.getProperty("env101.var1");
log.info("Environment Получение конфигурации {}", var1);
}
}
@ValueаннотациядаSpring
框架提供из用于注入Конфигурациясвойствоценитьизаннотация,Его можно использовать на занятияхпеременные-члены
、параметры метода
иКонструктор
Параметры,Это важно помнить!
существование приложение запускается,используйте @Value аннотированный Bean будет создан экземпляр. Все сипользовать @Value аннотированный Bean будет добавлен в PropertySourcesPlaceholderConfigurer
в коллекции постпроцессора.
Когда постпроцессор начинает выполнение, он читает Bean Все в @Value Аннотируйте отмеченное значение и присвойте проанализированное значение атрибута отмеченному значению посредством отражения. @Value аннотированныйпеременные-члены、параметры методаи Конструкторпараметр。
нужно внимание,существоватьиспользовать @Value При аннотации необходимо убедиться, что введенное значение атрибута загружено в Spring контейнер, иначе инъекция не удастся.
существоватьsrc/main/resources
в каталогеapplication.yml
Конфигурациядокументсерединадобавить вenv101.var1
свойство。
env101:
var1: var1-Официальный аккаунт: Программист Сяофу
Просто добавьте аннотацию к переменной @Value("${env101.var1}")
Вот и все,@Value аннотациявстречаавтоматический Воля Конфигурациядокументсерединаизenv101.var1
свойствоценить注入приезжатьvar1
Полесередина,Запустите модульный тест и посмотрите результаты.
@Slf4j
@SpringBootTest
public class EnvVariablesTest {
@Value("${env101.var1}")
private String var1;
@Test
public void var1Test(){
log.info("Настроить атрибут документа: {}",var1);
}
}
Без всякого ожидания данные конфигурации были успешно получены.
Хотя метод @Valueаннотация очень прост, если его выполнить неправильно, вы столкнетесь со многими подводными камнями.
Если в коде есть ссылка на переменную, а значение не присвоено в файле конфигурации, произойдет ошибка, аналогичная показанной ниже.
Чтобы избежать таких ошибок, вызывающих исключения при запуске службы, мы можем присвоить переменной значение по умолчанию при ссылке на нее, чтобы гарантировать, что программа может работать нормально, даже если значение присвоено неправильно.
@Value("${env101.var1:Я да, да}")
частная строка var1;
Существует также общееиспользовать Непонимание,Сразуда Воля @Value К статическим переменным добавляются аннотации, и значения атрибутов таким образом получить невозможно. Статические переменные — это атрибуты класса, а не атрибуты объекта. Spring выполняет внедрение зависимостей на основе свойств объектов. В это время статические переменные класса инициализируются. Компонент еще не создан, поэтому передать его невозможно. @Value Внедрить значения свойств.
@Slf4j
@SpringBootTest
public class EnvVariablesTest {
@Value("${env101.var1}")
private static String var1;
@Test
public void var1Test(){
log.info("Настроить атрибут документа: {}",var1);
}
}
Даже если аннотацию @Value нельзя использовать непосредственно для статических переменных, мы все равно можем присваивать значения статическим переменным, получая значение свойства существующего экземпляра Bean и присваивая его статической переменной.
мы можем пройти первыми @Value Аннотации внедряют значения атрибутов в обычные Бин, а затем получить Bean对应изсвойствоценить,А Воля его значение присваивается статической переменной Вот так.,Вы можете сохранить значение атрибута в статической переменной.
@Slf4j
@SpringBootTest
public class EnvVariablesTest {
private static String var3;
private static String var4;
@Value("${env101.var3}")
public void setVar3(String var3) {
var3 = var3;
}
EnvVariablesTest(@Value("${env101.var4}") String var4){
var4 = var4;
}
public static String getVar4() {
return var4;
}
public static String getVar3() {
return var3;
}
}
@Value аннотациядобавить вfinal
Чего нельзя сказать о ключевых словах.получатьсвойствоценить,потому что final Переменные должны быть инициализированы в конструкторе и не могут быть изменены после назначения. и @Value Аннотация находится в bean Внедрение свойства выполняется после создания экземпляра, поэтому его нельзя инициализировать в конструкторе. final переменная.
@Slf4j
@SpringBootTest
public class EnvVariables2Test {
private final String var6;
@Autowired
EnvVariables2Test( @Value("${env101.var6}") String var6) {
this.var6 = var6;
}
/**
* @valueаннотация final получать
*/
@Test
public void var1Test() {
log.info("final инъекция: {}", var6);
}
}
Только отмечено@Component
、@Service
、@Controller
、@Repository
или @Configuration
ждатьУправление контейнерамианнотированныйдобрый,Зависит от Spring управление bean серединаиспользовать @Valueаннотация вступит в силу. Для обычных POJO-классов использовать невозможно Аннотация @Value выполняет внедрение атрибутов.
/**
* @valueаннотация Незарегистрированный класс медиумиспользования
* `@Component`、`@Service`、`@Controller`、`@Repository` или `@Configuration` ждать
* Управление контейнерамианнотированныйдобрыйсерединаиспользовать @Valueаннотация вступит в силу
*/
@Data
@Slf4j
@Component
public class TestService {
@Value("${env101.var7}")
private String var7;
public String getVar7(){
return this.var7;
}
}
Если мы хотим получить TestService Значение атрибута переменной в классе требует внедрения зависимостей, но не использования. new способ. Создано посредством внедрения зависимостей TestService Объект, Весна Требуемые значения свойств объекта вводятся в объект при его создании.
/**
* @valueаннотация Неправильная цитата
*/
@Test
public void var7_1Test() {
TestService testService = new TestService();
log.info("Неправильная цитата инъекция: {}", testService.getVar7());
}
наконец Подвести Попробуйте Аннотация @Value должна быть в использование может вступить в силу в течение жизненного цикла компонента.
@ConfigurationProperties
аннотацияда SpringBoot Предоставляет более удобный способ обработки значений атрибутов в файлах конфигурации. Он может автоматически привязывать набор атрибутов с указанным префиксом к объекту Bean с помощью таких механизмов, как автоматическая привязка и преобразование типов.
существовать Springboot Запустите процесс загрузки конфигурации prepareEnvironment()
В методе есть важный пошаговый метод bindToSpringApplication(environment)
,что он делаетда Воля Конфигурациядокументсерединаизсвойствоценить绑定приезжатьодеяло @ConfigurationProperties
аннотация отмечена Бин-объект. Но в настоящее время эти объекты не были Spring Управление контейнерами, поэтому автоматическое внедрение свойств невозможно.
Итак, когда же эти объекты Bean были зарегистрированы в контейнере Spring?
Это включает в себя ConfigurationPropertiesBindingPostProcessor
класс, это Бин-постпроцессор, отвечающий за сканирование контейнеров в одеяле @ConfigurationProperties отмечено аннотациями Бин-объект. Если он найден, он будет использован Binder Компоненты привязывают к себе значения внешних свойств, тем самым обеспечивая возможность автоматического внедрения.
bindToSpringApplication
Основное значение атрибута да Воля привязано к Bean в объекте;ConfigurationPropertiesBindingPostProcessor
Ответственныйсуществовать Spring Воля была аннотация при запуске контейнера отмечена Bean Объект регистрируется в контейнере, и последующие операции по внедрению атрибутов завершаются;Демоиспользовать @ConfigurationProperties аннотация,существовать application.yml Добавьте элементы конфигурации в файл конфигурации:
env101:
var1: var1-Официальный аккаунт: Программист Сяофу
var2: var2-Официальный аккаунт: Программист Сяофу
Создайте MyConf добрый Используется для переноса всех префиксов какenv101
из Конфигурациясвойство。
@Data
@Configuration
@ConfigurationProperties(prefix = "env101")
public class MyConf {
private String var1;
private String var2;
}
существоватьнуждатьсяиспользоватьvar1
、var2
свойствоценитьиз地方,Воля MyConf Объект можно внедрить в зависимый объект.
@Slf4j
@SpringBootTest
public class ConfTest {
@Resource
private MyConf myConf;
@Test
public void myConfTest() {
log.info("@ConfigurationPropertiesаннотация Получение конфигурации {}", JSON.toJSONString(myConf));
}
}
В дополнение к системному стандарту application.yml
или ВОЗ application.properties
документснаружи,Нам также может потребоваться использовать настроенный документ конфигурации для достижения более гибкой и персонализированной конфигурации. да отличается от документа конфигурации по умолчанию,Пользовательский конфигурационный документ не может быть применен автоматически.,Нам нужно указать нагрузку вручную.
@PropertySources
аннотированный Принцип реализации относительно прост,Сканировать все классы, отмеченные этой аннотацией, при запуске приложения.,получатьприезжатьаннотациясередина Укажите индивидуальный Конфигурациядокументпуть,Воля指定路径下из Конфигурациядокументсодержаниенагрузкаприезжать Environment , так что ты можешь пройти @Value
аннотацияили Environment.getProperty()
Метод для получения определенного в нем значения атрибута.
существовать src/main/resources/ Создайте собственный файл конфигурации в каталоге xiaofu.properties
,Добавьте два атрибута.
env101.var9=var9-Программист Сяофу
env101.var10=var10-Программист Сяофу
существующие необходимо добавить в класс использования документа пользовательской конфигурации. @PropertySources
аннотация, аннотация Путь к пользовательскому файлу конфигурации указывается в атрибуте value. Можно указать несколько путей, разделенных запятыми.
@Data
@Configuration
@PropertySources({
@PropertySource(value = "classpath:xiaofu.properties",encoding = "utf-8"),
@PropertySource(value = "classpath:xiaofu.properties",encoding = "utf-8")
})
public class PropertySourcesConf {
@Value("${env101.var10}")
private String var10;
@Value("${env101.var9}")
private String var9;
}
Конфигурация успешно получена
нодакогда я попробуюнагрузка.yaml
документчас,Произошла ошибка при запуске проекта,После некоторых исследований я узнал,@PropertySources аннотация Только встроенныйPropertySourceFactory
адаптер。также Сразудасказать, что это может тольконагрузка.properties
документ.
Итак, если я хочунагрузкаодин.yaml
добрыйформадокумент,нонуждатьсясамореализацияyamlизадаптер YamlPropertySourceFactory
。
public class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
Properties properties = factory.getObject();
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
}
}
И существуетнагрузка для отображения при настройке указанного использования. YamlPropertySourceFactory
адаптер,Вот и все @PropertySourceаннотациянагрузка yaml-документа.
@Data
@Configuration
@PropertySources({
@PropertySource(value = "classpath:xiaofu.yaml", encoding = "utf-8", factory = YamlPropertySourceFactory.class)
})
public class PropertySourcesConf2 {
@Value("${env101.var10}")
private String var10;
@Value("${env101.var9}")
private String var9;
}
Мы можем использовать YamlPropertiesFactoryBean
общий YAML Значения свойств из файла конфигурации внедряются в Bean середина.
@Configuration
public class MyYamlConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer yamlConfigurer() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("xiaofu.yml"));
configurer.setProperties(Objects.requireNonNull(yaml.getObject()));
return configurer;
}
}
может пройти @Value
аннотацияили Environment.getProperty()
Метод для получения значения свойства, определенного в нем.
@Slf4j
@SpringBootTest
public class YamlTest {
@Value("${env101.var11}")
private String var11;
@Test
public void myYamlTest() {
log.info("Yaml Получение конфигурации {}", var11);
}
}
Если вам не нравятся описанные выше способы чтения конфигураций,Я просто хочу сам написать более популярное колесо,Это тоже легко。Мы вводим напрямуюPropertySources
получатьвсесвойствоиз Конфигурацияочередь,Чего еще вы хотите добиться с помощью аннотации?,Вы можете делать все, что захотите.
@Slf4j
@SpringBootTest
public class CustomTest {
@Autowired
private PropertySources propertySources;
@Test
public void customTest() {
for (PropertySource<?> propertySource : propertySources) {
log.info("Настроить получение Получение конфигурации name {} ,{}", propertySource.getName(), propertySource.getSource());
}
}
}
Мы можем пройти @Value
аннотация、Environment
добрый、@ConfigurationProperties
аннотация、@PropertySource
Аннотации и другие методы используются для получения информации о конфигурации.
Среди них аннотация @Value подходит для введения одного значения.,И несколько других методов подходят для пакетной обработки.Конфигурацияиз注入。разные способысуществоватьэффективность、гибкость、Простота использованияждать Аспекты существуютсуществоватьразница,существоватьвыбирать Получение конфигурации Способчас,Также необходимо учитывать личные привычки программирования и потребности бизнеса.
Если вы цените читабельность и удобство сопровождения вашего кода, вы можете выбрать использовать @ConfigurationProperties
аннотация Если вы уделяете больше внимания операционной эффективности, вы можете выбратьиспользование; Environment
добрый. Короче говоря, разные сценарии требуют разных методов для достижения оптимальных результатов.
Я Сяофу, увидимся в следующий раз~
Вышеуказанный адрес дела:https://github.com/chengxy-nds/Springboot-Notebook