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:
Following will be the final project directory structure for this example:
Let’s add the content mentioned in above directory structure.
<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.
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>
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.
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 + "]"; } }
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.
References
If you like tutorials on this site, why not take a step further and connect me on Facebook , Google Plus & Twitter as well? I would love to hear your thoughts on these articles, it will help improve further our learning process.
In this post we will be developing a full-blown CRUD application using Spring Boot, AngularJS, Spring Data, JPA/Hibernate and MySQL,…
Spring Boot complements Spring REST support by providing default dependencies/converters out of the box. Writing RESTful services in Spring Boot…
Being able to start the application as standalone jar is great, but sometimes it might not be possible to run…
Spring framework has taken the software development industry by storm. Dependency Injection, rock solid MVC framework, Transaction management, messaging support,…
Let's secure our Spring REST API using OAuth2 this time, a simple guide showing what is required to secure a…
This post shows how an AngularJS application can consume a REST API which is secured with Basic authentication using Spring…
View Comments
Why do you do all of that and then use getBean()?
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.
And If I am not wrong ; You cant Autowire inside a static class .