Skip to main content
Chapter 5 of 18 · 7 sections

Spring: Creating and Wiring Beans

Explore component scanning, qualifiers, generic injection, FactoryBean, and prototype dependencies.

Original chapter: Creating and using beans. The text and examples below are preserved from the historical source; read the corrections above before using them.

Section 5.1: Autowiring all beans of a specific type

If you've got multiple implementations of the same interface, Spring can autowire them all into a collection object. I'm going to use an example using a Validator pattern1

Foo Class:

Source example · PDF page 19
public class Foo {
    private String name;
    private String emailAddress;
    private String errorMessage;
     /** Getters & Setters omitted **/
}

Interface:

Source example · PDF page 19
public interface FooValidator {
   public Foo validate(Foo foo);
}

Name Validator Class:

Source example · PDF page 19
@Component(value="FooNameValidator")
public class FooNameValidator implements FooValidator {
   @Override
   public Foo validate(Foo foo) {
        //Validation logic goes here.
   }
}

Email Validator Class:

Source example · PDF page 19
@Component(value="FooEmailValidator")
public class FooEmailValidator implements FooValidator {
   @Override
   public Foo validate(Foo foo) {
        //Different validation logic goes here.
   }
}

You can now autowire these validators individually or together into a class.

Interface:

Source example · PDF page 19
public interface FooService {
   public void handleFoo(Foo foo);
}

Class:

Source example · PDF page 19
@Service
public class FooServiceImpl implements FooService {
    /** Autowire all classes implementing FooValidator interface**/
   @Autowired
   private List<FooValidator> allValidators;

   @Override
   public void handleFoo(Foo foo) {
       /**You can use all instances from the list**/
      for(FooValidator validator : allValidators) {
          foo = validator.validate(foo);
      }
   }
}

It's worth noting that if you have more than one implementation of an interface in the Spring IoC container and don't specify which one you want to use with the @Qualifier annotation, Spring will throw an exception when trying to start, because it won't know which instance to use.

1: This is not the right way to do such simple validations. This is a simple example about autowiring. If you want an idea of a much easier validation method look up how Spring does validation with annotations.

Section 5.2: Basic annotation autowiring

Interface:

Source example · PDF page 20
public interface FooService {
   public int doSomething();
}

Class:

Source example · PDF page 20
@Service
public class FooServiceImpl implements FooService {
   @Override
   public int doSomething() {
        //Do some stuff here
       return 0;
   }
}

It should be noted that a class must implement an interface for Spring to be able to autowire this class. There is a method to allow Spring to autowire stand-alone classes using load time weaving, but that is out of scope for this example.

You can gain access to this bean in any class that instantiated by the Spring IoC container using the @Autowired annotation.

Usage:

Source example · PDF page 20
@Autowired([required=true])

The @Autowired annotation will first attempt to autowire by type, and then fall back on bean name in the event of ambiguity.

This annotation can be applied in several different ways.

Constructor injection:

Source example · PDF page 20
public class BarClass() {
   private FooService fooService
   @Autowired
   public BarClass(FooService fooService) {
       this.fooService = fooService;
   }
}

Field injection:

Source example · PDF page 21
public class BarClass() {
   @Autowired
   private FooService fooService;
}

Setter injection:

Source example · PDF page 21
public class BarClass() {
   private FooService fooService;

   @Autowired
   public void setFooService(FooService fooService) {
       this.fooService = fooService;
   }
}

Section 5.3: Using FactoryBean for dynamic bean instantiation

In order to dynamically decide what beans to inject, we can use FactoryBeans. These are classes which implement the factory method pattern, providing instances of beans for the container. They are recognized by Spring and can be used transparently, without need to know that the bean comes from a factory. For example:

Source example · PDF page 21
public class ExampleFactoryBean extends AbstractFactoryBean<String> {
    // This method determines the type of the bean for autowiring purposes
   @Override
   public Class<?> getObjectType() {
       return String.class;
   }

    // this factory method produces the actual bean
   @Override
   protected String createInstance() throws Exception {
        // The thing you return can be defined dynamically,
        // that is read from a file, database, network or just
        // simply randomly generated if you wish.
       return "Something from factory";
   }
}

Configuration:

Source example · PDF page 21
@Configuration
public class ExampleConfig {
   @Bean
   public FactoryBean<String> fromFactory() {
       return new ExampleFactoryBean();
   }
}

Getting the bean:

Source example · PDF page 22
AbstractApplicationContext context = new AnnotationConfigApplicationContext(ExampleConfig.class);
String exampleString = (String) context.getBean("fromFactory");

To get the actual FactoryBean, use the ampersand prefix before the bean's name:

Source example · PDF page 22
FactoryBean<String> bean = (FactoryBean<String>) context.getBean("&fromFactory");

Please note that you can only use prototype or singleton scopes - to change the scope to prototype override isSingleton method:

Source example · PDF page 22
public class ExampleFactoryBean extends AbstractFactoryBean<String> {
   @Override
   public boolean isSingleton() {
       return false;
   }

    // other methods omitted for readability reasons
}

Note that scoping refers to the actual instances being created, not the factory bean itself.

Section 5.4: Declaring Bean

To declare a bean, simply annotate a method with the @Bean annotation or annotate a class with the @Component annotation (annotations @Service, @Repository, @Controller could be used as well).

When JavaConfig encounters such a method, it will execute that method and register the return value as a bean within a BeanFactory. By default, the bean name will be that of the method name.

We can create bean using one of three ways:

1. Using Java based Configuration: In Configuration file we need to declare bean using @bean annotation

Source example · PDF page 22
     @Configuration
     public class AppConfig {
         @Bean
         public TransferService transferService() {
             return new TransferServiceImpl();
         }
     }

2. Using XML based configuration: For XML based configuration we need to create declare bean in application configuration XML i.e.

Source example · PDF page 22
      <beans>
          <bean name="transferService" class="com.acme.TransferServiceImpl"/>
      </beans>

3. Annotation-Driven Component: For annotation-driven components, we need to add the @Component annotation to the class we want to declare as bean.

Source example · PDF page 22
      @Component("transferService")
      public class TransferServiceImpl implements TransferService {
          ...
      }

Now all three beans with name transferService are available in BeanFactory or ApplicationContext.

Section 5.5: Autowiring specific bean instances with @Qualifier

If you've got multiple implementations of the same interface, Spring needs to know which one it should autowire into a class. I'm going to use a Validator pattern in this example.1

Foo Class:

Source example · PDF page 23
public class Foo {
    private String name;
    private String emailAddress;
    private String errorMessage;
     /** Getters & Setters omitted **/
}

Interface:

Source example · PDF page 23
public interface FooValidator {
   public Foo validate(Foo foo);
}

Name Validator Class:

Source example · PDF page 23
@Component(value="FooNameValidator")
public class FooNameValidator implements FooValidator {
   @Override
   public Foo validate(Foo foo) {
        //Validation logic goes here.
   }
}

Email Validator Class:

Source example · PDF page 23
@Component(value="FooEmailValidator")
public class FooEmailValidator implements FooValidator {
   @Override
   public Foo validate(Foo foo) {
        //Different validation logic goes here.
   }
}

You can now autowire these validators individually into a class.

Interface:

Source example · PDF page 23
public interface FooService {
   public void handleFoo(Foo foo);
}

Class:

Source example · PDF page 24
@Service
public class FooServiceImpl implements FooService {
    /** Autowire validators individually **/
   @Autowired
    /*
    * Notice how the String value here matches the value
    * on the @Component annotation? That's how Spring knows which
    * instance to autowire.
    */
   @Qualifier("FooNameValidator")
   private FooValidator nameValidator;

   @Autowired
   @Qualifier("FooEmailValidator")
   private FooValidator emailValidator;

   @Override
   public void handleFoo(Foo foo) {
        /**You can use just one instance if you need**/
       foo = nameValidator.validate(foo);
   }
}

It's worth noting that if you have more than one implementation of an interface in the Spring IoC container and don't specify which one you want to use with the @Qualifier annotation, Spring will throw an exception when trying to start, because it won't know which instance to use.

1: This is not the right way to do such simple validations. This is a simple example about autowiring. If you want an idea of a much easier validation method look up how Spring does validation with annotations.

Section 5.6: Autowiring specific instances of classes using generic type parameters

If you've got an interface with a generic type parameter, Spring can use that to only autowire implementations that implement a type parameter you specify.

Interface:

Source example · PDF page 24
public interface GenericValidator<T> {
   public T validate(T object);
}

Foo Validator Class:

Source example · PDF page 24
@Component
public class FooValidator implements GenericValidator<Foo> {
   @Override
   public Foo validate(Foo foo) {
        //Logic here to validate foo objects.
   }
}

Bar Validator Class:

Source example · PDF page 24
@Component
public class BarValidator implements GenericValidator<Bar> {
   @Override
   public Bar validate(Bar bar) {
        //Bar validation logic here
   }
}

You can now autowire these validators using type parameters to decide which instance to autowire.

Interface:

Source example · PDF page 25
public interface FooService {
   public void handleFoo(Foo foo);
}

Class:

Source example · PDF page 25
@Service
public class FooServiceImpl implements FooService {
    /** Autowire Foo Validator **/
   @Autowired
   private GenericValidator<Foo> fooValidator;

   @Override
   public void handleFoo(Foo foo) {
       foo = fooValidator.validate(foo);
   }
}

Section 5.7: Inject prototype-scoped beans into singletons

The container creates a singleton bean and injects collaborators into it only once. This is not the desired behavior when a singleton bean has a prototype-scoped collaborator, since the prototype-scoped bean should be injected every time it is being accessed via accessor.

There are several solutions to this problem:

1. Use lookup method injection

2. Retrieve a prototype-scoped bean via javax.inject.Provider

3. Retrieve a prototype-scoped bean via org.springframework.beans.factory.ObjectFactory (an equivalent of #2, but with the class that is specific to Spring)

4. Make a singleton bean container aware via implementing ApplicationContextAware interface

Approaches #3 and #4 are generally discouraged, since they strongly tie an app to Spring framework. Thus, they are not covered in this example.

Lookup method injection via XML configuration and an abstract method

Java Classes

Source example · PDF page 25
public class Window {
}

public abstract class WindowGenerator {

   public Window generateWindow() {
       Window window = createNewWindow(); // new instance for each call
       ...
   }
   protected abstract Window createNewWindow(); // lookup method
}

XML

Source example · PDF page 26
<bean id="window" class="somepackage.Window" scope="prototype" lazy-init="true"/>

<bean id="windowGenerator" class="somepackage.WindowGenerator">
   <lookup-method name="createNewWindow" bean="window"/>
</bean>

Lookup method injection via Java configuration and @Component

Java Classes

Source example · PDF page 26
public class Window {
}

@Component
public class WindowGenerator {

   public Window generateWindow() {
       Window window = createNewWindow(); // new instance for each call
       ...
   }

   @Lookup
   protected Window createNewWindow() {
       throw new UnsupportedOperationException();
   }
}

Java configuration

Source example · PDF page 26
@Configuration
@ComponentScan("somepackage") // package where WindowGenerator is located
public class MyConfiguration {

   @Bean
   @Lazy
   @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
   public Window window() {
       return new Window();
   }
}

Manual lookup method injection via Java configuration

Java Classes

Source example · PDF page 26
public class Window {
}

public abstract class WindowGenerator {

   public Window generateWindow() {
       Window window = createNewWindow(); // new instance for each call
       ...
   }
   protected abstract Window createNewWindow(); // lookup method
}

Java configuration

Source example · PDF page 27
@Configuration
public class MyConfiguration {

   @Bean
   @Lazy
   @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
   public Window window() {
       return new Window();
   }

   @Bean
   public WindowGenerator windowGenerator(){
       return new WindowGenerator() {
           @Override
           protected Window createNewWindow(){
               return window();
           }
       };
   }
}

Injection of a protoype-scoped bean into singleton via javax.inject.Provider

Java classes

Source example · PDF page 27
public class Window {
}

public class WindowGenerator {

   private final Provider<Window> windowProvider;

   public WindowGenerator(final Provider<Window> windowProvider) {
       this.windowProvider = windowProvider;
   }

   public Window generateWindow() {
       Window window = windowProvider.get(); // new instance for each call
       ...
   }
}

XML

Source example · PDF page 27
<bean id="window" class="somepackage.Window" scope="prototype" lazy-init="true"/>

<bean id="windowGenerator" class="somepackage.WindowGenerator">
   <constructor-arg>
       <bean class="org.springframework.beans.factory.config.ProviderCreatingFactoryBean">
           <property name="targetBeanName" value="window"/>
       </bean>
   </constructor-arg>
</bean>

The same approaches can be used for other scopes as well (e.g. for injection a request-scoped bean into singleton).

Buy me a coffee
Daily Practice
0/0