How does Spring "magically" know which Bean type to use?

Viewed 72

Using Spring 5, I was puzzled as to how exactly the AnnotationConfigApplicationContext "magically" knows to use the correct implementation of my interface, since the references are to the interface not the implementing class.

Illustration

Note: Irrelevant code such as imports and unrelated behaviour has been ommitted

An interface CleaningTool and two implementing classes Broom and VacuumCleaner, with variations on the interface's method doCleanJob()

public interface CleaningTool {
    void doCleanJob();
}
public class Broom implements CleaningTool {
    @Override
    public void doCleanJob() {
        System.out.println("Sweep sweep sweep");
    }
}
public class VacuumCleaner implements CleaningTool {
    @Override
    public void doCleanJob() {
        System.out.println("Zoom zoom zoom");
    }
}

Then, my AnnotationConfigApplicationContex uses my class AppConfig thusly:

@Configuration
public class AppConfig {
    @Bean
    public CleaningTool broom(){
        return new Broom();
    }

    @Bean
    public CleaningTool vacuum(){
        return new VacuumCleaner();
    }
}

Finally, in my MainApp class, where I invoke the AnnotationConfigApplicationContext's getBean() method, is where I tested this puzzling phenomenon which I, at first, expected not to work:

public class MainApp {
    public static void main(String[] args) {

        ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

        CleaningTool vacuum = ctx.getBean(VacuumCleaner.class);
        vacuum.doCleanJob();

    }
}

Console output: Zoom zoom zoom

Even though my reference types in both my AppConfig and MainApp were CleaningTool, Spring somehow knew to seek out the Bean that matched the class VacuumCleaner.class, in such a way that the VacuumCleaner's behaviour was used.

How does this "magic" work?

1 Answers

@Configuration is meant to provide a tool to define beans. Spring creates these beans (instances of classes) and stores them in the ApplicationContext.

You can think of the Application Context as a map that contains mapping between ids / classes of actual beans to the actual instances of corresponding singletons.

So when spring starts it creates both Broom and VacuumCleaner and places both of these beans into application context.

Then the application context is "ready" and you call the following line:

CleaningTool vacuum = ctx.getBean(VacuumCleaner.class);

Note, that you don't ask for the interface CleaningTool but for concrete class VacuumCleaner. In this case spring goes to its internal mappings and just retrieves the value (actual object) by concrete class. No magic here :)

Related