A simple IoC + DI Spring example

In the previous posts I have written a puny Spring Boot application example sporting a trivial RESTful controller Let's spice it up a bit, extracting the business logic from the controller and putting it in a hierarchy of classes. The interesting part of it is that I am going to do it using IoC (Inversion of Control) and DI (Dependency Injection).

I created a sub-package named control, and in it I put an interface, Greeter, that exposes the only method I really care of:
public interface Greeter {
    String greeting();
}
Then I refactored my GreetingController to use that interface to do the dirty job. Something like this:
public class GreetingController {
    private Greeter greeter;

    public String greeting() {
        return greeter.greeting();
    }
}
The reason for doing this should be clear. My controller won't care about the details of how a greeting is generated. It just knows that exists a hierarchy of classes rooted in the Greeter interface, and it would call its greeting() method when it intercepts a user call for this job.

Then I created a couple of concrete classes implementing Greeter. A mock one, thought to be used just in development, and the actual stuff designed to be used in production.
public class MockGreeter implements Greeter {
    private static final Log log = LogFactory.getLog(MockGreeter.class);

    @Override
    public String greeting() {
        log.debug("Generating mock greeting");
        return "mock hello!";
    }
}

public class PlainGreeter implements Greeter {
    private static final Log log = LogFactory.getLog(PlainGreeter.class);

    @Override
    public String greeting() {
        log.trace("Generating plain greeting");
        return "Hello!";
    }
}
I know, it is not easy to spot a difference between them. Let's assume they will grow and diverge to something more useful in the future.

The interesting stuff here is defining how the controller should know which Greeter to use. In the old pre-IoC days it would be its job to create a dependency with the selected Greeter, creating an object of a concrete type. Nowadays we prefer to do the other way round, we invert the control, and let the concrete Greeter signal its availability to be used by the controller to the framework (in this case Spring). We can do that in a few different ways, being annotation usually considered the preferred one.

The controller should tell to Spring in some way that a field it owns should be injected with a dependency (here is where DI enters in the game). There are a few ways to do it. I usually prefer to annotate the data member, like this:
@RestController
public class GreetingController {
    @Resource
    private Greeter greeter;

    // ...
}
On the other side, each Greeter implementation that could be selected from Spring for the controller should show it up:
@Component
public class MockGreeter implements Greeter {
    // ...
}
We still have a problem. We have two different implementations of Greeter competing to be injected to the controller. Which one should Spring choose?

One way of solving it is by configuration. We specify the spring.profiles.active property in the Spring application.properties file giving to it a value that would act as a selector for the appropriate Greeter. In my case, I want to play with two different configurations, dev and prod. When in development (dev) I want the mock greeter to be injected in the controller, while in production (prod) the plain greeter should be used.

In case of production my Spring configuration file would have this line in it:
spring.profiles.active=prod
My Greeter classes would be annotated in this way:
@Component
@Profile("prod")
public class PlainGreeter implements Greeter {
// ...
}

@Component
@Profile("!prod")
public class MockGreeter implements Greeter {
// ...
}

The complete Spring Boot project is on github. The relevant files are

No comments:

Post a Comment