Controlando a ordem de criação do bean com a anotação @DependsOn
1. Visão geral
O Spring, por padrão, gerencia o ciclo de vida dos beans e organiza sua ordem de inicialização.
Mas ainda podemos personalizá-lo com base em nossas necessidades. We can choose either the SmartLifeCycle interface or the @DependsOn annotation for managing initialization order.
Este tutorial explora a anotação@DependsOn e seu comportamento no caso de um bean ausente oucircular dependency. Ou no caso de simplesmente precisar de um bean inicializado antes de outro.
2. Maven
Em primeiro lugar, vamos importar a dependência do contexto spring em nosso arquivopom.xml. Devemos sempre consultar o Maven Central parathe latest version de dependências:
org.springframework
spring-context
5.1.4.RELEASE
3. @DependsOn
Devemos usar esta anotação para especificar dependências de bean. Spring guarantees that the defined beans will be initialized before attempting an initialization of the current bean.
Digamos que temos umFileProcessor que depende de aFileReadereFileWriter. Nesse caso,FileReader eFileWriter devem ser inicializados antes deFileProcessor.
4. Configuração
O arquivo de configuração é uma classe Java pura com anotação@Configuration:
@Configuration
@ComponentScan("com.example.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 specifies its dependencies with @DependsOn. Também podemos anotar umComponent com@DependsOn:
@Component
@DependsOn({"filereader", "fileWriter"})
public class FileProcessor {}
5. Uso
Vamos criar uma classeFile. Cada um dos beans atualiza o texto emFile. FileReader o atualiza conforme lido. FileWriter o atualiza conforme a escrita eFileProcessor atualiza o texto conforme processado:
@Test
public void WhenFileProcessorIsCreated_FileTextContains_Processed() {
FileProcessor processor = context.getBean(FileProcessor.class);
assertTrue(processor.process().endsWith("processed"));
}
5.1. Dependência ausente
Em caso de dependência ausente, o Spring lança umBeanCreationException com uma exceção base deNoSuchBeanDefinitionException. Leia mais sobreNoSuchBeanDefinitionExceptionhere.
Por exemplo, o beandummyFileProcessor depende de um beandummyFileWriter. ComodummyFileWriter não existe, ele lançaBeanCreationException:
@Test(expected=NoSuchBeanDefinitionException.class)
public void whenDependentBeanNotAvailable_ThrowsNosuchBeanDefinitionException(){
context.getBean("dummyFileProcessor");
}
5.2. Dependência circular
Além disso, neste caso, ele lançaBeanCreationExceptione destaca que os grãos têm uma dependência circular:
@Bean("dummyFileProcessorCircular")
@DependsOn({"dummyFileReaderCircular"})
@Lazy
public FileProcessor dummyFileProcessorCircular() {
return new FileProcessor(file);
}
Circular dependencies can happen if a bean has an eventual dependency on itself, criando um círculo:
Bean1 -> Bean4 -> Bean6 -> Bean1
6. Pontos chave
Finalmente, existem alguns pontos que devemos cuidar ao usar a anotação@DependsOn:
-
Ao usar@DependsOn,, devemos usar a verificação de componentes
-
Se uma classe anotada emDependsOn for declarada via XML, os metadados de anotaçãoDependsOn serão ignorados
7. Conclusão
@DependsOn torna-se especialmente útil ao construir sistemas com requisitos de dependência complexos.
Isso facilita a injeção de dependência, garantindo que o Spring tenha lidado com toda a inicialização daqueles Beans necessários antes de carregar nossa classe dependente.
Como sempre, o código pode ser encontradoover on GitHub.