Inversion of Control – Part III – Dependency Injection in Java Spring I

Pivotal Java Spring Logo

As I explained in the blog post about Inversion of Control, your code can be controlled not only by implementing an IoC Design Pattern within your code, by a framework that controls (part of) your code, but also by an entity, that you don’t have direct control over, such as a Servlet Container that controls your code in a certain behaviour. Java Spring is a framework that takes control over part of your code. One of the key features of Spring is an extensive use of Dependency Injection.

Components in Spring

Firstly, Spring manages your beans; in this case, instances of Java classes. You can tell Spring which instances of classes should be controlled by Spring by either using annotations or XML-configuration files. In this introduction, I will solely focus on annotations, to not cause too much confusion. I will focus on XML-configuration in a later blog post.

Alle components that Spring should take control of, have to be annotated. The most basic annotation is @Component on a class level.

package com.vividbreeze.spring;

import org.springframework.stereotype.Component;

@Component
public class FormalGreeting {
    public void sayHello() {
        System.out.println("Good day, Madam or Sir. How may I assist you?");
    }
}

Spring now needs to know that it should take control of this bean. Spring does this by a so-called ComponentScan

package com.vividbreeze.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
public class GreetingExample {

    public static void main (String args[]) {

        ApplicationContext context =
                new AnnotationConfigApplicationContext(GreetingExample.class);

        context.getBean(FormalGreeting.class).sayHello();
    }
}

Spring scans all classes in the package com.vividbreeze.spring (and its sub-packages by default) that are annotated with (@Component). These classes (beans) are then instantiated and controlled by the BeanFactory. This BeanFactory can be accessed via the ApplicationContext. The ApplicationContext is bound to the class that is annotated with @ComponentScan. Notice, that the component scan is performed, not until the ApplicationContext is created (new ApplicationConfigApplicationContext(…)).

You can access a bean under Spring with context.getBean (bean-name). By default, beans are singletons, i.e. only one shared instance of a bean will be managed by Spring. The other option would be non-singleton, i.e. everytime you access a bean with getBean (...) a new instance will be created. The BeanFactory stores beans either by the class-name or a separate bean-name, that you pass as an attribute to the Component annotation.

@Component ("commonGreeting")
public class FormalGreeting implements Greeting {
    public void sayHello() {
        System.out.println("Good day, Madam or Sir. How may I assist you?");
    }
}
@ComponentScan
public class GreetingExample {

    public static void main (String args[]) {

        ApplicationContext context =
                new AnnotationConfigApplicationContext(GreetingExample.class);

        ((FormalGreeting)context.getBean("commonGreeting")).sayHello();
    }
}

 

Dependency Injection in Spring (autowiring)

This might only seem of a minor benefit so far. The real advantage of Spring is the so-called auto-wiring, where instances of beans are injected into other beans. You can either inject dependencies on an attribute level (as shown above) or on a setter or on the constructor.

Attribute Level Dependency Injection

package com.vividbreeze.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class GreetingProcessor {

    @Autowired
    private FormalGreeting greeting;

    public void process() {
        greeting.sayHello();
    }
}

When Spring scans the classes annotated with @Component, the BeanFactory will instantiate GreetingProcessor and FormalGreeting. It will then see that GreetingProcessor contains an @Autowired attribute of type FormalGreeting. The BeanFactory finds a bean with the name “FormalGreeting” and wires it to greeting in the GreetingProcessor Bean.

So far this is an advantage, as you don’t have to worry about instantiating (and managing) dependencies anymore.

Setter Dependency Injection

When you use setter injection during runtime you might notice that the bean was not injected and is null. You can avoid this by annotating the setter with @Required.

package com.vividbreeze.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class GreetingProcessor {

    private FormalGreeting greeting;

    @Autowired
    public void setFormalGreeting(FormalGreeting greeting) {
        this.greeting = greeting;
    }

    public void process() {
        greeting.sayHello();
    }
}

Class Dependency Injection

package com.vividbreeze.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class GreetingProcessor {

    private FormalGreeting greeting;

    @Autowired
    public GreetingProcessor (FormalGreeting greeting) {
        this.greeting = greeting;
    }

    public void process() {
        greeting.sayHello();
    }
}

Circular Dependencies

We might have dependencies like this: Bean A is instantiated with Bean B, which in turn is instantiated with Bean C. In this case, Spring creates bean C first, then Bean B and injects Bean C into it, then it will create bean A and injects bean B into it.

There might be some situations where the dependencies are circular, i.e. bean A is instantiated with bean B that, in turn, instantiate with bean A.

@Component
public class ComponentA {

    private ComponentB componentB;

    @Autowired
    private ComponentA (ComponentB componentB) {
        this.componentB = componentB;
    }
}
@Component
public class ComponentB {

    private ComponentA componentA;

    @Autowired
    private ComponentB(ComponentA componentA) {
        this.componentA = componentA;
    }
}
@ComponentScan
public class CircularComponentExample {
    public static void main (String args[]) {

        ApplicationContext context =
                new AnnotationConfigApplicationContext(CircularComponentExample.class);

        context.getBean(ComponentA.class);
    }
}

In the console, you will see something like this

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'componentA': Requested bean is currently in creation: Is there an unresolvable circular reference?

It might seem like a far-fetched example, however, in reality, this happens once in a while especially if you have complex nested dependencies between objects. How can you solve the problem? Simply, try to solve circular dependencies by breaking them up or use attribute or setter-injection, as here the injections are fully resolved when the attribute is used the first time. In the next example, the componentA bean is created upon request when calling context.getBean (ComponentA.class). Alternatively, you can use setter-injection.

@Component
public class ComponentA {

    @Autowired
    private ComponentB componentB;

    private ComponentA () {
        //
    }
}
@Component
public class ComponentB {

    @Autowired
    private ComponentA componentA;

    private ComponentB() {
    }
}

In the console, you can see how Spring is now handling the situation

08:10:32.536 [main] DEBUG ...DefaultListableBeanFactory - Eagerly caching bean 'org.springframework.context.event.internalEventListenerFactory' to allow for resolving potential circular references
08:10:32.539 [main] DEBUG ...DefaultListableBeanFactory - Finished creating instance of bean 'org.springframework.context.event.internalEventListenerFactory'
08:10:32.539 [main] DEBUG ...DefaultListableBeanFactory - Creating shared instance of singleton bean 'circularComponentExample'
08:10:32.539 [main] DEBUG ...DefaultListableBeanFactory - Creating instance of bean 'circularComponentExample'
08:10:32.539 [main] DEBUG ...DefaultListableBeanFactory - Eagerly caching bean 'circularComponentExample' to allow for resolving potential circular references
08:10:32.541 [main] DEBUG ...DefaultListableBeanFactory - Finished creating instance of bean 'circularComponentExample'
08:10:32.541 [main] DEBUG ...DefaultListableBeanFactory - Creating shared instance of singleton bean 'componentA'
08:10:32.541 [main] DEBUG ...DefaultListableBeanFactory - Creating instance of bean 'componentA'
08:10:32.545 [main] DEBUG ...InjectionMetadata - Registered injected element on class [com.vividbreeze.spring.ComponentA]: AutowiredFieldElement for private com.vividbreeze.spring.ComponentB com.vividbreeze.spring.ComponentA.componentB
08:10:32.545 [main] DEBUG ...DefaultListableBeanFactory - Eagerly caching bean 'componentA' to allow for resolving potential circular references
08:10:32.547 [main] DEBUG ...InjectionMetadata - Processing injected element of bean 'componentA': AutowiredFieldElement for private com.vividbreeze.spring.ComponentB com.vividbreeze.spring.ComponentA.componentB
08:10:32.548 [main] DEBUG org.springframework.core.annotation.AnnotationUtils - Failed to meta-introspect annotation interface ...Autowired: java.lang.NullPointerException
08:10:32.552 [main] DEBUG ...DefaultListableBeanFactory - Creating shared instance of singleton bean 'componentB'
08:10:32.552 [main] DEBUG ...DefaultListableBeanFactory - Creating instance of bean 'componentB'
08:10:32.553 [main] DEBUG ...InjectionMetadata - Registered injected element on class [com.vividbreeze.spring.ComponentB]: AutowiredFieldElement for private com.vividbreeze.spring.ComponentA com.vividbreeze.spring.ComponentB.componentA
08:10:32.553 [main] DEBUG ...DefaultListableBeanFactory - Eagerly caching bean 'componentB' to allow for resolving potential circular references
08:10:32.554 [main] DEBUG ...InjectionMetadata - Processing injected element of bean 'componentB': AutowiredFieldElement for private com.vividbreeze.spring.ComponentA com.vividbreeze.spring.ComponentB.componentA
08:10:32.554 [main] DEBUG org.springframework.core.annotation.AnnotationUtils - Failed to meta-introspect annotation interface ...Autowired: java.lang.NullPointerException
08:10:32.554 [main] DEBUG ...DefaultListableBeanFactory - Returning eagerly cached instance of singleton bean 'componentA' that is not fully initialized yet - a consequence of a circular reference
08:10:32.555 [main] DEBUG ...AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'componentB' to bean named 'componentA'
08:10:32.556 [main] DEBUG ...DefaultListableBeanFactory - Finished creating instance of bean 'componentB'
08:10:32.556 [main] DEBUG ...AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'componentA' to bean named 'componentB'
08:10:32.556 [main] DEBUG ...DefaultListableBeanFactory - Finished creating instance of bean 'componentA'
08:10:32.556 [main] DEBUG ...DefaultListableBeanFactory - Returning cached instance of singleton bean 'componentB'

There are other ways to deal with circular dependencies in Spring, such as the @Lazy annotation, where the injected bean creation will be completed when first used (and before as a proxy bean), the @PostConstruct and other.  I recommend, whenever possible, to try to avoid circular dependencies.

 

Remarks

You will find many discussion about which form of Dependency Injection to use. Personally, I find that dependencies should be made visible to others that use the class. Hence I avoid attribute injection, although it seems more elegant, especially if you want to inject many dependencies. However, if you have many dependencies in one class, it can be an indication of bad design and concerns might be not separated well enough. Fewer dependencies make a class easier to test and easier to understand. Constructor injection avoids that dependencies are set after the instantiation of a class and hence can be controlled from the outside. If this is changing the dependency during runtime, a setter to inject a dependency makes this clearly visible to others.

The benefit of using Dependency Injection in Spring is that the IoC container of Spring dissolves, especially complex and nested injection chains. Hence it does a great deal of work from developers.

This short introduction should give you a good base to learn more about Dependency Injection in Spring. Of course, there is more to DI in Spring. In the next blog post, I will use the Spring Framework with the example from the previous blog post.

Chris