Методология разработки приложений с двенадцатью факторами настоятельно рекомендует «строгое отделение конфигурации от кода» [1]
Spring Cloud предлагает решение этой проблемы с помощью Spring Cloud Config Server. Spring Cloud Config Server определяет себя следующим образом.
«Spring Cloud Config обеспечивает поддержку на стороне сервера и клиента для внешней конфигурации в распределенной системе. С помощью Config Server у вас есть центральное место для управления внешними свойствами приложений во всех средах »[2]
Централизованное управление конфигурацией - очень простая и очень эффективная функция. Отсутствие централизованной настройки очень часто приводит к ошибкам.
Еще одна хорошая функция - после изменения конфигурации вы можете легко получить их из своего приложения без перезапуска. Существует множество руководств, демонстрирующих, как создать сервер конфигурации и обновить свойство во время выполнения. Я считаю, что ПОЧЕМУ-СТАТЬИ важнее, чем КАК-СТАТЬЯ. Поэтому я не утверждаю, как создать сервер конфигурации и т. Д. Я хочу описать, почему мы используем свойства конфигурации при обновлении свойств во время выполнения.
Если вы выполните поиск в сети, есть множество ресурсов, которые просто показывают область обновления на контроллере, как показано ниже.
@EnableAutoConfiguration
@ComponentScan
@RestController
@RefreshScope // important!
public class SpringApp {
@Value("${bar:World!}")
String bar;
@RequestMapping("/")
String hello() {
return "Hello " + bar + "!";
}
public static void main(String[] args) {
SpringApplication.run(SpringApp.class, args);
}
}
Но выбрать область обновления в нужном месте непросто, как показано. Позвольте мне подумать о сценарии ниже
test:
value: MyTestValue
Контроллер:
@RestController("/test")
public class TestController {
private final TestService testService;
public TestController(TestService testService) {
this.testService = testService;
}
@GetMapping("/v1")
public String test() {
return testService.getValueWithDelay();
}
@GetMapping("/v2")
public String test2() {
return testService.getValue();
}
}
Услуга:
@RefreshScope
@Service
public class TestService {
@Value("${test.value}")
private String value;
public String getValueWithDelay() {
try {
Thread.sleep(30000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return value;
}
public String getValue() {
return value;
}
}
Звоните http://127.0.0.1:8080/test/v1. Задержка составляет 30 секунд. Он возвращается через 30 секунд.
Звоните «http://127.0.0.1:8080/test/v2. Он возвращается через 6 миллисекунд.
Вроде все идеально. Давайте изменим сценарий.
- Звоните http://127.0.0.1:8080/test/v1
- Измените тестовое значение на MyTestValueChanged
- Обновить свойства localhost: 8080 / активатор / обновить
- Звонок «http://127.0.0.1:8080/test/vpа2
Конечная точка V2 возвращается через 10–20 секунд или около того. (Эти операции необходимо завершить до завершения выполнения версии 1)
Мы использовали область обновления в классе обслуживания. Если значение, которое используется внутри класса обслуживания, то другие методы будут ждать, пока это значение не будет заменено контекстом. В нашей современной среде разработки программного обеспечения важны даже миллисекунды. V1 и V2 - разные операции, но они блокируют друг друга из-за использования области обновления. Хуже того, очень проблематичным становится отслеживание того, какое значение повлияет на какую услугу.
В этот момент включается концепция свойств конфигурации. Если вы используете область обновления в свойствах конфигурации, а не в сервисе, то можно разрешить блокировку разных сервисов друг друга. Поскольку контекст обновляет только свойства конфигурации bean. И свойство освежения происходит очень быстро. Вот почему вам следует использовать свойство конфигурации и использовать внутри него область обновления.
@RefreshScope
@Configuration
@ConfigurationProperties(prefix = "test")
public class TestConfiguration {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Услуга:
@Service
public class TestService {
private final TestConfiguration testConfiguration;
public TestService(TestConfiguration testConfiguration) {
this.testConfiguration = testConfiguration;
}
public String getValueWithDelay() {
try {
Thread.sleep(30000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return testConfiguration.getValue();
}
public String getValue() {
return testConfiguration.getValue();
}
}
- Звоните http://127.0.0.1:8080/test/v1
- Измените тестовое значение на MyTestValueChangedAgain
- Обновить свойства localhost: 8080 / активатор / обновить
- Звоните http://127.0.0.1:8080/test/v2
Конечная точка V2 возвращается через 10 миллисекунд или около того. Нет блоков.
Задача решена.
PS: Особая благодарность Эркану Сормазу.
Использованная литература: