Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

NPI – Spring Top – Temp – Non-Geo (Lightrun)

Get started with Spring 5 and Spring Boot 2, through the reference Learn Spring course:

>> LEARN SPRING
NPI – Lightrun – Spring (partner)

We rely on other people’s code in our own work. Every day. It might be the language you’re writing in, the framework you’re building on, or some esoteric piece of software that does one thing so well you never found the need to implement it yourself.

The problem is, of course, when things fall apart in production - debugging the implementation of a 3rd party library you have no intimate knowledge of is, to say the least, tricky. It’s difficult to understand what talks to what and, specifically, which part of the underlying library is at fault.

Lightrun is a new kind of debugger.

It's one geared specifically towards real-life production environments. Using Lightrun, you can drill down into running applications, including 3rd party dependencies, with real-time logs, snapshots, and metrics. No hotfixes, redeployments, or restarts required.

Learn more in this quick, 5-minute Lightrun tutorial:

>> The Essential List of Spring Boot Annotations and Their Use Cases

1. Overview

Spring, by default, manages beans' lifecycle and arranges their initialization order.

But, we can still customize it based on our needs. We can choose either the SmartLifeCycle interface or the @DependsOn annotation for managing initialization order.

This tutorial explores the @DependsOn annotation and its behavior in case of a missing bean or circular dependency. Or in case of simply needing one bean initialized before another.

2. Maven

First of all, let's import spring-context dependency in our pom.xml file. We should always refer to Maven Central for the latest version of dependencies:

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

3. @DependsOn

We should use this annotation for specifying bean dependencies. Spring guarantees that the defined beans will be initialized before attempting an initialization of the current bean.

Let's say we have a FileProcessor which depends on a FileReader and FileWriter. In this case, FileReader and FileWriter should be initialized before the FileProcessor.

4. Configuration

The configuration file is a pure Java class with @Configuration annotation:

@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 specifies its dependencies with @DependsOn. We can also annotate a Component with @DependsOn:

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

5. Usage

Let us create one class File. Each of the beans updates the text within File. FileReader updates it as read. FileWriter updates it as write and FileProcessor updates the text as processed:

@Test
public void WhenFileProcessorIsCreated_FileTextContains_Processed() {
    FileProcessor processor = context.getBean(FileProcessor.class);
    assertTrue(processor.process().endsWith("processed"));
}

5.1. Missing Dependency

In case of missing dependency, Spring throws a BeanCreationException with a base exception of NoSuchBeanDefinitionException. Read more about NoSuchBeanDefinitionException here.

For example, dummyFileProcessor bean depends on a dummyFileWriter bean. Since dummyFileWriter doesn't exist, it throws BeanCreationException:

@Test(expected=NoSuchBeanDefinitionException.class)
public void whenDependentBeanNotAvailable_ThrowsNosuchBeanDefinitionException(){
    context.getBean("dummyFileProcessor");
}

5.2. Circular Dependency

Also, in this case, it throws BeanCreationException and highlights that the beans have a circular dependency:

@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, creating a circle:

Bean1 -> Bean4 -> Bean6 -> Bean1

6. Key Points

Finally, there are few points which we should take care of while using @DependsOn annotation:

  • While using @DependsOn, we must use component-scanning
  • If a DependsOn-annotated class is declared via XML, DependsOn annotation metadata is ignored

7. Conclusion

@DependsOn becomes especially useful when building systems with complex dependency requirements.

It facilitates the Dependency Injection, ensuring that Spring will have handled all of the initialization of those required Beans before loading our dependent class.

As always, the code can be found over on GitHub.

Spring bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> THE COURSE
Generic footer banner
Comments are closed on this article!