Spring Annotation Based Container Configuration


Overview

Starting from Spring 2.5 it became possible to configure the dependency injection using annotations. So instead of using XML to describe a bean wiring, you can move the bean configuration into the component class itself by using annotations on the relevant class, method, or field declaration.
Important: Annotation injection is performed before XML injection, thus the latter configuration will override the former for properties wired through both approaches.

Why Spring Configuration with Annotations?

  1. XML configuration can be verbose
  2. Easy to configure your Spring beans with Annotations
  3. Annotations minimize the XML configuration

Spring Annotation Based Configuration Basics

How to enable annotation-based wiring?

Annotation wiring is not turned on in the Spring container by default. So, before we can use annotation-based wiring, we will need to enable it in our Spring configuration file. So consider the following configuration file in case you want to use any annotation in your Spring application.
<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context = "http://www.springframework.org/schema/context"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>
   <!-- bean definitions go here -->

</beans>
Once <context:annotation-config /> is configured, you can start annotating your code to indicate that Spring should automatically wire values into properties, methods, and constructors.
Let's discuss different annotations that Spring provides to configure annotation-based metadata configuration.
  • @Required
  • @Autowired
  • @Qualifier
  • @Primary
  • @Resource
  • @PostConstruct and @PreDestroy (These are JSR-250 annotations)

@Required

The @Required annotation is method-level annotation and applied to the setter method of a bean.
This annotation simply indicates that the setter method must be configured to be dependency-injected with a value at configuration time.


This annotation simply indicates that the affected bean property must be populated at configuration time, through an explicit property value in a bean definition or through autowiring.

@Autowired

We can use the @Autowired to mark a dependency which Spring is going to resolve and inject. We can use this annotation with a constructor, setter, or field injection.

Constructor injection

class Car {
    private Engine engine;
 
    @Autowired
    Car(Engine engine) {
        this.engine = engine;
    }
}

Setter injection

class Car {
    private Engine engine;
 
    @Autowired
    void setEngine(Engine engine) {
        this.engine = engine;
    }
}

Field injection

class Car {
    @Autowired
    private Engine engine;
}
Read more about the importance of @Autowired annotation on Spring @Autowired Annotation with Example

@Primary Annotation

Use @Primary to give higher preference to a bean when there are multiple beans of the same type.
Let’s describe the problem in detail.

Why is @Primary Needed?
In some cases, we need to register more than one bean of the same type.
In this example we have mySQLConnection() and oracleConnection() beans of the Connection type:
@Configuration
public class Config {
 
    @Bean
    public Connection mySQLConnection() {
        return new MySQLConnection();
    }
 
    @Bean
    public Connection oracleConnection() {
        return new OracleConnection();
    }
}
Spring throws NoUniqueBeanDefinitionException if we try to run the application.
To access beans with the same type we usually use @Qualifier(“beanName”) annotation.
We apply to at the injection point along with @Autowired. In our case, we select the beans at the configuration phase so @Qualifier can’t be applied here. We can learn more about @Qualifier annotation by following the link.
To resolve this issue Spring offers the @Primary annotation. The following example shows how to use @Primaryannotation in a spring application.
The @Primary annotation may be used on any class directly or indirectly annotated with @Component or on factory methods annotated with @Bean. In this example, we will use @Primary annotation with @Componentannotation.
Read more about the importance of @Primary annotation on Spring - @Primary Annotation Example

@Qualifier

We use @Qualifier annotation to resolve ambiguous dependencies.
  1. This annotation helps fine-tune annotation-based autowiring. There may be scenarios when we create more than one bean of the same type and want to wire only one of them with a property. This can be controlled using @Qualifier annotation along with the @Autowired annotation.
  2. The @Qualifier is used to resolve ambiguous dependencies i.e, it helps @Autowired annotations to choose one of the dependency.
If there are multiple implementations for a single interface then we can use @Qualifier to choose required implementation at runtime.
Example :
@Autowired 
@Qualifier("datasource") 
private DataSource datasource; 

@Autowired 
@Qualifier("datasource1") 
private DataSource datasource;
Read more about the importance of @Qualifier annotation on Spring @Qualifier Annotation Example

@Resource

Spring also supports injection using the JSR-250 @Resource annotation on fields or bean property setter methods
public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource(name="myMovieFinder")
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}
If no name is specified explicitly, the default name is derived from the field name or setter method.

@PostConstruct and @PreDestroy

Spring supports JSR-250 lifecycle annotations.

Consider DatabaseInitiaizer bean, whose init() and destroy() methods are annotated with @PostConstruct and @PreDestroy annotations respectively.

DatabaseInitiaizer.java

package net.javaguides.spring;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.stereotype.Component;

@Component
public class DatabaseInitiaizer {

    private List < User > listOfUsers = new ArrayList < > ();

    @PostConstruct
    public void init() {
        User user = new User(1, "User");
        User user1 = new User(2, "Admin");
        User user2 = new User(3, "SuperAdmin");

        listOfUsers.add(user);
        listOfUsers.add(user1);
        listOfUsers.add(user2);
        System.out.println("-----------List of users added in init() method ------------");
        for (Iterator < User > iterator = listOfUsers.iterator(); iterator.hasNext();) {
            User user3 = (User) iterator.next();
            System.out.println(user3.toString());
        }
        // save to database

    }

    @PreDestroy
    public void destroy() {
        // Delete from database
        listOfUsers.clear();
        System.out.println("-----------After of users removed from List in destroy() method ------------");
        for (Iterator < User > iterator = listOfUsers.iterator(); iterator.hasNext();) {
            User user3 = (User) iterator.next();
            System.out.println(user3.toString());
        }
    }
}
Refer complete example of @PostConstruct and @PreDestroy annotations on Spring @PostConstruct and @PreDestroy Example

Are annotations better than XML for configuring Spring?

I think the answer is it depends like each approach has its pros and cons, and usually, it is up to the developer to decide which strategy suits them better. Due to the way they are defined, annotations provide a lot of context in their declaration, leading to shorter and more concise configuration. However, XML excels at wiring up components without touching their source code or recompiling them. Some developers prefer having the wiring close to the source while others argue that annotated classes are no longer POJOs and, furthermore, that the configuration becomes decentralized and harder to control.
No matter the choice, Spring can accommodate both styles and even mix them together. It’s worth pointing out that through its JavaConfig option, Spring allows annotations to be used in a non-invasive way, without touching the target components source code and that in terms of tooling, all configuration styles are supported by the Spring Tool Suite.

Conclusion

In this post, we have learned the what is spring annotation based container configuration, how to enable annotation configuration and we also have seen few annotations like @Autowired, @Qualifier, @Primary, @Required and Spring supports JSR-250 based annotations which include @Resource, @PostConstruct, and @PreDestroy annotations.

Comments