1. Обзор
Spring по умолчанию управляет жизненным циклом бинов и устанавливает порядок их инициализации.
Но мы все еще можем настроить его в соответствии с нашими потребностями. Мы можем выбрать либо интерфейс SmartLifeCycle , либо аннотацию
@DependsOn
для управления порядком инициализации .
В этом руководстве рассматривается аннотация @DependsOn
и ее поведение в случае отсутствия bean-компонента или циклической зависимости . Или в случае просто необходимости инициализации одного компонента перед другим.
2. Мавен
Прежде всего, давайте импортируем зависимость spring-context в наш файл pom.xml
. Мы всегда должны обращаться к Maven Central за последней версией зависимостей:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
3. @Зависит от
Мы должны использовать эту аннотацию для указания зависимостей компонентов. Spring гарантирует, что определенные bean-компоненты будут инициализированы перед попыткой инициализации текущего bean-компонента.
Допустим, у нас есть FileProcessor
, который зависит от FileReader
и FileWriter
. В этом случае FileReader
и FileWriter
должны быть инициализированы до FileProcessor
.
4. Конфигурация
Файл конфигурации представляет собой чистый класс Java с аннотацией @Configuration
:
@Configuration
@ComponentScan("com.foreach.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. Использование
Давайте создадим один класс File
. Каждый из 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);
}
Циклические зависимости могут возникать, если bean-компонент имеет возможную зависимость от самого себя , создавая круг:
Bean1 -> Bean4 -> Bean6 -> Bean1
6. Ключевые моменты
Наконец, есть несколько моментов, о которых мы должны позаботиться при использовании аннотации @DependsOn
:
- При использовании
@DependsOn
мы должны использовать сканирование компонентов - Если класс с аннотацией
DependsOn
объявлен через XML, метаданные аннотацииDependsOn игнорируются.
7. Заключение
@DependsOn
становится особенно полезным при создании систем со сложными требованиями к зависимостям.
Это облегчает внедрение зависимостей, гарантируя, что Spring выполнит всю инициализацию этих необходимых компонентов перед загрузкой нашего зависимого класса.
Как всегда, код можно найти на GitHub .