Categories: spring

Spring Auto-detection autowire & Component-scanning Example With Annotations

In this post we will see how Spring can auto-detect the beans configured in your application using component-scanning, wire them wherever required without even declaring as @Bean methods in @Configuration class ( or in XML terms, without declaring bean in Spring XML Configuration file). We will also see corresponding XML configuration side-by-side for comparison.

We will proceed with help of a typical enterprise level application setup example showing different layers(Service, DAO) involved in application development. Let’s get going.


Following technologies being used:

  • Spring 4.0.6.RELEASE
  • Joda-time 2.3
  • Maven 3
  • JDK 1.6
  • Eclipse JUNO Service Release 2

Project directory structure

Following will be the final project directory structure for this example:

Let’s add the content mentioned in above directory structure.

Step 1: Provide Spring dependencies in Maven pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.websystique.spring</groupId>
  <artifactId>Spring4AutoScanning</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <name>Spring4AutoScanning</name>
    <properties>
  <springframework.version>4.0.6.RELEASE</springframework.version>
  <joda-time.version>2.3</joda-time.version>
 </properties>

 <dependencies>
  <!--  Spring -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${springframework.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${springframework.version}</version>
  </dependency>

       <!-- Joda-Time -->  
  <dependency>
     <groupId>joda-time</groupId>
     <artifactId>joda-time</artifactId>
     <version>${joda-time.version}</version>
    </dependency>

   </dependencies>
 <build>
  <pluginManagement>
   <plugins>
    <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <version>3.2</version>
     <configuration>
      <source>1.6</source>
      <target>1.6</target>
     </configuration>
    </plugin>
   </plugins>
  </pluginManagement>
 </build>

</project>

We need Spring core and Spring context dependencies to work with this example. Additionally in our example we will be doing some date calculation using JodaTime LocalDate class, so joda-time dependency is in there.

Step 2: Create Spring Configuration Class

Spring configuration class are the ones annotated with @Configuration. These classes contains methods annotated with @Bean. These @Bean annotated methods generates beans managed by Spring container.


package com.websystique.spring.configuration;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "com.websystique.spring")
public class AppConfig {

}

You might have noticed that above class is Empty, no @Bean methods, acting as a placeholder instead. So where will the beans come from?

Actually, they will be auto-detected, thanks to @ComponentScan annotation.

@ComponentScan(basePackages = "com.websystique.spring")

@ComponentScan basePackages attribute takes package name[s] as input which will be search for to find any class annotated with Spring specific annotations.

Below are commonly used Spring annotation which makes a bean auto-detectable:

@Repository – Used to mark a bean as DAO Component on persistence layer
@Service – Used to mark a bean as Service Component on business layer
@Controller – Used to mark a bean as Controller Component on Presentation layer
@Configuration – Used to mark a bean as Configuration Component.
@Component – General purpose annotation, can be used as a replacement for above annotations.

Note that all above mentioned annotations are internally annotated with @Component, so indeed you can use @Component everywhere, but to keep the design & intention clean, it’s advisable to use different annotation based on different condition.

Remark: In our example, you can even discard the Configuration class altogether as it does not contain any @Bean method. We will see how to scan the beans in that case below.

Same Configuration in XML terms can be expressed as below (let’s name it app-config.xml)

<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-4.0.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 
 <context:component-scan base-package="com.websystique.spring" />
 
</beans>

Step 3: Create DAO Layer Classes


package com.websystique.spring.dao;

import com.websystique.spring.model.Employee;

public interface EmployeeDao {

 void saveInDatabase(Employee employee);
}

package com.websystique.spring.dao;

import org.springframework.stereotype.Repository;

import com.websystique.spring.model.Employee;

@Repository("employeeDao")
public class EmployeeDaoImpl implements EmployeeDao{

 public void saveInDatabase(Employee employee) {

  /*
   * Logic to save in DB goes here
   */  System.out.println("Employee "+employee.getName()+" is registered for assessment on "+ employee.getAssessmentDate());
  
 }

}

@Repository annotation marks this class as an Auto-detectable bean on persistence layer. Parameter to this annotation employeeDao provides a name to this bean. We will inject this class into main service bean.

Step 4: Create Service Layer Classes


package com.websystique.spring.service;

import org.joda.time.LocalDate;

public interface DateService {

 LocalDate getNextAssessmentDate();
}



package com.websystique.spring.service;

import org.joda.time.LocalDate;
import org.springframework.stereotype.Service;

@Service("dateService")
public class DateServiceImpl implements DateService{

 public LocalDate getNextAssessmentDate() {
  return new LocalDate(2015,10,10);
 }

}

@Service marks this class as Auto-detectable bean on business layer. We will inject this class into main service bean.


package com.websystique.spring.service;

import com.websystique.spring.model.Employee;

public interface EmployeeService {

 void registerEmployee(Employee employee);
}


package com.websystique.spring.service;

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

import com.websystique.spring.dao.EmployeeDao;
import com.websystique.spring.model.Employee;

@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService{

 @Autowired
 private DateService dateService;
 
 @Autowired
 private EmployeeDao employeeDao;
 

 public void registerEmployee(Employee employee) {
  employee.setAssessmentDate(dateService.getNextAssessmentDate());
  employeeDao.saveInDatabase(employee);
 }
 
}

EmployeeService is our main service class.Notice that we have injected both DateService and EmployeeDao in this.
@Autowired on dateService property marks the DateService to be auto-wired by Spring’s dependency injection with the appropriate bean in Spring context. In our case, we have already declared a DateService bean using @Service, so that bean will be injected here. Similarly, employeeDao will be injected by EmployeeDao annotated with @Repository.

Below is the model class Employee used in our example


package com.websystique.spring.model;

import org.joda.time.LocalDate;

public class Employee {

 private int id;

 private String name;

 private LocalDate assessmentDate;

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public LocalDate getAssessmentDate() {
  return assessmentDate;
 }

 public void setAssessmentDate(LocalDate assessmentDate) {
  this.assessmentDate = assessmentDate;
 }

 @Override
 public String toString() {
  return "Employee [id=" + id + ", name=" + name + ", assessmentDate="
    + assessmentDate + "]";
 }

}

Step 5: Create Main to run as Java Application


package com.websystique.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

import com.websystique.spring.configuration.AppConfig;
import com.websystique.spring.model.Employee;
import com.websystique.spring.service.EmployeeService;

public class AppMain {

 public static void main(String args[]){
  AbstractApplicationContext  context = new AnnotationConfigApplicationContext(AppConfig.class);
  
  EmployeeService service = (EmployeeService) context.getBean("employeeService");

  /*
   * Register employee using service
   */  Employee employee = new Employee();
  employee.setName("Danny Theys");
  service.registerEmployee(employee);
  
  context.close();
 }
}

Run above program as Java Application, you should see following output

Employee Danny Theys is registered for assessment on 2015-10-10

Now, in case you decided to discard the configuration class AppConfig you can do so with following changes

package com.websystique.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.websystique.spring.model.Employee;
import com.websystique.spring.service.EmployeeService;

public class AppMain {

 public static void main(String args[]){
  //AbstractApplicationContext  context = new AnnotationConfigApplicationContext(AppConfig.class);
  AnnotationConfigApplicationContext  context = new AnnotationConfigApplicationContext();
  context.scan("com.websystique.spring"); 
  context.refresh();

  EmployeeService service = (EmployeeService) context.getBean("employeeService");

  /*
   * Register employee using service
   */  Employee employee = new Employee();
  employee.setName("Danny Theys");
  service.registerEmployee(employee);
  
  context.close();
 }
}

AnnotationConfigApplicationContext.scan method performs a scan of all class in specified package[s], registering all the beans annotated with @Component (even @configuration itself is internally annotated with @component) in application context. A caveat here is that refresh must be called after scan in order to fully process the registered classes.

Run above program as Java Application, you should see same output as before.

That’s it.

For XML based configuration , replace

 AbstractApplicationContext  context = new AnnotationConfigApplicationContext(AppConfig.class);

with

AbstractApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml");

in above main, no other changes. Run the program and you will see same output.

Download Source Code


References

View Comments

    • Hi Peadar, getBean is only used inside Main, & that too because i am handling application context manually.

      • It's better practice to Autowire the bean so you don't have to call getBean() on it. Look into SpringBeanAutowiringSupport

        • Thanks for Your comment. However, as i mentioned, this is the Main class [not a spring component, no @Component or other annotations is used here, although we may use it, but in this example, we are not], and thus i am getting the context manually, and eventually get the Bean. With Spring components, i do use @Autowired as in this post.

Share
Published by

Recent Posts

Spring Boot + AngularJS + Spring Data + JPA CRUD App Example

In this post we will be developing a full-blown CRUD application using Spring Boot, AngularJS, Spring Data, JPA/Hibernate and MySQL,…

8 years ago

Spring Boot Rest API Example

Spring Boot complements Spring REST support by providing default dependencies/converters out of the box. Writing RESTful services in Spring Boot…

8 years ago

Spring Boot WAR deployment example

Being able to start the application as standalone jar is great, but sometimes it might not be possible to run…

8 years ago

Spring Boot Introduction + hello world example

Spring framework has taken the software development industry by storm. Dependency Injection, rock solid MVC framework, Transaction management, messaging support,…

8 years ago

Secure Spring REST API using OAuth2

Let's secure our Spring REST API using OAuth2 this time, a simple guide showing what is required to secure a…

8 years ago

AngularJS+Spring Security using Basic Authentication

This post shows how an AngularJS application can consume a REST API which is secured with Basic authentication using Spring…

8 years ago