使用@DependsOn注解控制Bean创建顺序

2023/05/13

1. 概述

默认情况下,Spring管理bean的生命周期并安排它们的初始化顺序。

但是,我们仍然可以根据需要对其进行自定义,我们可以通过SmartLifeCycle接口或@DependsOn注解来管理初始化顺序。

2. Maven依赖


<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.13</version>
</dependency>

3. @DependsOn

我们应该使用这个注解来指定bean依赖。Spring保证在尝试初始化当前bean之前先初始化定义的bean。

假设我们有一个依赖于FileReader和FileWriter的FileProcessor,在这种情况下,FileReader和FileWriter应该在FileProcessor之前初始化。

4. 配置


@Configuration
@ComponentScan("cn.tuyucheng.taketoday.dependson")
public class Config {

    @Bean("fileProcessor")
    @DependsOn({"fileReader", "fileWriter"})
    public FileProcessor fileProcessor() {
        return new FileProcessor(file);
    }

    @Bean("fileReader")
    public FileReader fileReader() {
        return new FileReader(file);
    }

    @Bean("fileWriter")
    public FileWriter fileWriter() {
        return new FileWriter(file);
    }
}

FileProcessor使用@DependsOn指定其依赖bean,我们还可以使用@DependsOn标注组件类:


@Component
@DependsOn({"filereader", "fileWriter"})
public class FileProcessor {
}

5. 用法

我们创建一个File文件,每个bean都会更新File中的text属性。 FileReader将其更新为read,FileWriter将其更新为write并且FileProcessor将文本更新为processed:


@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = TestConfig.class)
public class FileProcessorIntegrationTest {

    @Autowired
    ApplicationContext context;

    @Autowired
    File file;

    @Test
    public void whenAllBeansCreated_FileTextEndsWithProcessed() {
        context.getBean("fileProcessor");
        assertTrue(file.getText().endsWith("processed"));
    }
}

5.1 缺少依赖bean

在缺少依赖bean的情况下,Spring抛出一个BeanCreationException,其中包含一个基本异常NoSuchBeanDefinitionException。

例如,dummyFileProcessor bean依赖于dummyFileWriter bean。 由于dummyFileWriter不存在,它会抛出BeanCreationException:

class FileProcessorIntegrationTest {

    @Test
    void whenDependentBeanNotAvailable_ThrowsNoSuchBeanDefinitionException() {
        assertThrows(BeanCreationException.class, () -> context.getBean("dummyFileProcessor"));
    }
}

5.2 循环依赖

此外,在这种情况下,它会抛出BeanCreationException并突出显示bean具有循环依赖关系:


@Configuration
@ComponentScan("cn.tuyucheng.taketoday.dependson")
public class TestConfig {

    @Autowired
    File file;

    @Bean("dummyFileProcessorCircular")
    @DependsOn({"dummyFileReaderCircular"})
    @Lazy
    public FileProcessor dummyFileProcessorCircular() {
        return new FileProcessor(file);
    }

    @Bean("dummyFileReaderCircular")
    @DependsOn({"dummyFileProcessorCircular"})
    @Lazy
    public FileReader dummyFileReaderCircular() {
        return new FileReader(file);
    }
}

如果bean最终依赖于自身,就会发生循环依赖,从而产生一个循环

Bean1 -> Bean4 -> Bean6 -> Bean1

6. 关键点

最后,在使用@DependsOn注解时,我们应该注意以下几点:

  • 在使用@DependsOn时,我们必须使用组件扫描
  • 如果通过XML声明@DependsOn注解类,则忽略@DependsOn注解元数据。

7. 总结

在构建具有复杂依赖需求的系统时,@DependsOn特别有用。

它可以确保Spring在加载我们的依赖类之前已经处理了那些所需Bean的所有初始化。 与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章