Java – Which classes should be autowired by Spring (when to use dependency injection)

dependency-injectionjavaspring

I have been using Dependency Injection in Spring for some time now, and I understand how it works and what are some pros and cons of using it. However, when I'm creating a new class I often wonder – Should this class be managed by Spring IOC Container?

And I don't want to talk about differences between @Autowired annotation, XML configuration, setter injection, constructor injection, etc. My question is a general one.

Let's say we have a Service with a Converter:

@Service
public class Service {

    @Autowired
    private Repository repository;

    @Autowired
    private Converter converter;

    public List<CarDto> getAllCars() {
        List<Car> cars = repository.findAll();
        return converter.mapToDto(cars);
    }
}

@Component
public class Converter {

    public CarDto mapToDto(List<Car> cars) {
        return new ArrayList<CarDto>(); // do the mapping here
    }
}

Clearly, the converter doesn't have any dependencies, so it's not necessary for it to be autowired. But for me it seems better as autowired. Code is cleaner and easy to test. If I write this code without DI, the service will look like that:

@Service
public class Service {

    @Autowired
    private Repository repository;

    public List<CarDto> getAllCars() {
        List<Car> cars = repository.findAll();
        Converter converter = new Converter();
        return converter.mapToDto(cars);
    }
}

Now it's much more difficult to test it. Moreover, new converter will be created for every convert operation, even though it's always in the same state, which seems like an overhead.

There are some well known patterns in Spring MVC: Controllers using Services and Services using Repositories. Then, if Repository is autowired (which it usually is), then Service has to be autowired too. And this is quite clear. But when do we use @Component annotation? If you have some static util classes (like converters, mappers) – do you autowire them?

Do you try to make all classes autowired? Then all the class dependencies are easy to inject (once again, easy to understand and easy to test). Or do you try to autowire only when it's absolutely necessary?

I've spent some time looking for some general rules on when to use autowiring, but I couldn't find any specific tips. Usually, people talk about "do you use DI? (yes/no)" or "what type of dependency injection do you prefer", which doesn't answer my question.

I would be grateful for any tips concerning this topic!

Best Answer

Agree with @ericW's comment, and just want to add remember you can use initializers to keep your code compact:

@Autowired
private Converter converter;

or

private Converter converter = new Converter();

or, if the class really has no state at all

private static final Converter CONVERTER = new Converter();

One of the key criteria for whether Spring should instantiate and inject a bean is, is that bean so complicated that you want to mock it in testing? If so, then inject it. For example, if converter makes a round trip to any external system, then make it a component instead. Or if the return value has a big decision tree with dozens of possible variations based on the input, then mock it. And so forth.

You've already done a good job of rolling up that functionality and encapsulating it, so now it's just a question of whether it's complex enough to be considered a separate "unit" for testing.