«1. Обзор
Spring по умолчанию управляет жизненным циклом бинов и устанавливает порядок их инициализации.
Но мы все еще можем настроить его в соответствии с нашими потребностями. Мы можем выбрать либо интерфейс SmartLifeCycle, либо аннотацию @DependsOn для управления порядком инициализации.
В этом руководстве рассматривается аннотация @DependsOn и ее поведение в случае отсутствия bean-компонента или циклической зависимости. Или в случае просто необходимости инициализации одного компонента перед другим.
2. Maven
Прежде всего, давайте импортируем зависимость spring-context в наш файл pom.xml. Мы всегда должны обращаться к Maven Central за последней версией зависимостей:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
3. @DependsOn
Мы должны использовать эту аннотацию для указания зависимостей компонентов. Spring гарантирует, что определенные bean-компоненты будут инициализированы перед попыткой инициализации текущего bean-компонента.
Допустим, у нас есть FileProcessor, который зависит от FileReader и FileWriter. В этом случае FileReader и FileWriter должны быть инициализированы до FileProcessor.
4. Конфигурация
Файл конфигурации представляет собой чистый класс Java с аннотацией @Configuration:
@Configuration
@ComponentScan("com.baeldung.dependson")
public class Config {
@Bean
@DependsOn({"fileReader","fileWriter"})
public FileProcessor fileProcessor(){
return new FileProcessor();
}
@Bean("fileReader")
public FileReader fileReader() {
return new FileReader();
}
@Bean("fileWriter")
public FileWriter fileWriter() {
return new FileWriter();
}
}
FileProcessor указывает свои зависимости с помощью @DependsOn. Мы также можем аннотировать компонент с помощью @DependsOn:
@Component
@DependsOn({"filereader", "fileWriter"})
public class FileProcessor {}
5. Использование
Давайте создадим один файл класса. Каждый из bean-компонентов обновляет текст в файле File. FileReader обновляет его как прочитанный. FileWriter обновляет его по мере записи, а FileProcessor обновляет текст по мере обработки:
@Test
public void WhenFileProcessorIsCreated_FileTextContains_Processed() {
FileProcessor processor = context.getBean(FileProcessor.class);
assertTrue(processor.process().endsWith("processed"));
}
5.1. Отсутствует зависимость
В случае отсутствия зависимости Spring генерирует исключение BeanCreationException с базовым исключением NoSuchBeanDefinitionException. Подробнее об исключении NoSuchBeanDefinitionException читайте здесь.
Например, bean-компонент dummyFileProcessor зависит от bean-компонента dummyFileWriter. Так как dummyFileWriter не существует, он генерирует исключение BeanCreationException:
@Test(expected=NoSuchBeanDefinitionException.class)
public void whenDependentBeanNotAvailable_ThrowsNosuchBeanDefinitionException(){
context.getBean("dummyFileProcessor");
}
5.2. Циклическая зависимость
Кроме того, в этом случае генерируется BeanCreationException и подчеркивается, что компоненты имеют циклическую зависимость:
@Bean("dummyFileProcessorCircular")
@DependsOn({"dummyFileReaderCircular"})
@Lazy
public FileProcessor dummyFileProcessorCircular() {
return new FileProcessor(file);
}
Циклические зависимости могут возникать, если компонент имеет возможную зависимость от самого себя, создавая круг: ~~ ~
Bean1 -> Bean4 -> Bean6 -> Bean1
6. Ключевые моменты
Наконец, есть несколько моментов, о которых мы должны позаботиться при использовании аннотации @DependsOn:
-
При использовании @DependsOn мы должны использовать компонентное сканирование. объявленный через XML, метаданные аннотации DependsOn игнорируются
7. Заключение
@DependsOn становится особенно полезным при построении систем со сложными требованиями к зависимостям.
Это облегчает внедрение зависимостей, гарантируя, что Spring выполнит всю инициализацию этих необходимых компонентов перед загрузкой нашего зависимого класса.
Как всегда, код можно найти на GitHub.