1. Overview

In this tutorial, we're going to examine how we can initialize the Spring application context - in other words, the Spring container.

ApplicationContext is the central interface to provide configuration for a Spring application. There are different subclasses that work with different setups i.e. XML-based configuration, annotation-based configuration, etc. We'll be working with AnnotationConfigApplicationContext which is designed to work with annotation-based and Java-based Spring configurations.

2. Sample Application

Let's first examine our sample application.

We have GreetService and its only implementation DefaultGreetService:

public interface GreetService {

    void greet();
}

@Component
public class DefaultGreetService implements GreetService {

    @Override
    public void greet() {
        System.out.println("Greetings...");
    }
}

Then we have a basic @Configuration class, ApplicationConfiguration:

@Configuration
@ComponentScan
public class ApplicationConfiguration {
}

3. Register @Configuration Classes

Now, we'll initialize our application context by registering the @Configuration classes. There are several ways to accomplish this.

To begin with, we'll provide the @Configuration classes in the constructor:

private static void withConfigurationsInConstructor() {
    ConfigurableApplicationContext applicationContext =
      new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
    
    final GreetService greetService = applicationContext.getBean(GreetService.class);
    greetService.greet();
    
    applicationContext.close();
}

In this example, we're creating an instance of AnnotationConfigApplicationContext with our @Configuration class. Although we're providing one here, it is also valid to provide multiple @Configuration classes. Then Spring reads the ApplicationConfiguration class and performs a component scan - since we have @ComponentScan in ApplicationConfiguration. As a result, it discovers our @Component class - DefaultGreetService. Then we're accessing this bean via the ApplicationContext.getBean method.

We can also register our @Configuration classes after we've created an ApplicationContext. It is similar in effect to the previous example:

private static void withRegistration() {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    applicationContext.register(ApplicationConfiguration.class);
    applicationContext.refresh();
    
    final GreetService greetService = applicationContext.getBean(GreetService.class);
    greetService.greet();
    
    applicationContext.close();
}

Here, we're creating an instance of AnnotationConfigApplicationContext and then registering our configuration class via ApplicationContext.register method. Note that we're calling ApplicationContext.refresh after the registration.

4. Register @Component Classes

Similar to the @Configuration classes, we'll now register our @Component classes when initializing the ApplicationContext. We can also apply the same approach for other annotated classes - @Repository, @Service, @Controller, etc. However, unless the component contains lite @Bean methods, Spring doesn't discover other beans through scanning or other means:

private static void withComponentsInConstructor() {
    ConfigurableApplicationContext applicationContext =
      new AnnotationConfigApplicationContext(DefaultGreetService.class);
    
    final GreetService greetService = applicationContext.getBean(GreetService.class);
    greetService.greet();
    
    applicationContext.close();
}

Here, we're passing DefaultGreetService.class to the constructor of AnnotationConfigApplicationContext. As a result, the Spring container holds only this bean.

5. Scan Packages

Next, we'll initialize our ApplicationContext by starting a component scan under the given base packages:

private static void withComponentScan() {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    applicationContext.scan(GreetService.class.getPackage().getName());
    applicationContext.refresh();
    
    final GreetService greetService = applicationContext.getBean(GreetService.class);
    greetService.greet();
    
    applicationContext.close();
}

In this example, we're calling the ApplicationContext.scan method with the package of GreetService. As a result, Spring discovers the annotated components under that package. Note that, for the scan operation to take effect we're calling ApplicationContext.refresh.

6.  Summary

In this tutorial, we've examined the different ways to initialize a Spring ApplicationContext. We mainly focused on the annotation-based and Java-based configurations using AnnotationConfigApplicationContext.

As always, the source code for all examples is available on Github.