lishman levelup
«previous  next»


Getting Started
Form Processing
IoC Container
Hibernate ORM



Auto-detecting Components in Spring MVC


We know that Spring will assemble our objects and inject the appropriate dependencies, but how does Spring determine which objects are to be injected?

Components

Spring auto-detects candidates for injection by scanning the package specified in the <context:component-scan> element, which we saw in our configuration file earlier. Any class which includes one of the @Component annotations, will be selected.

The @Component annotations are:
  • @Controlller - a web controller.
  • @Service - a business service facade.
  • @Repository - a data access object.
It should be obvious that the component based annotations represent the different layers in a three-tier architecture (presentation, business logic and data). We have already seen @Controller in action, and we cover @Repository in Hibernate ORM, so that just leaves @Service.

Service Component

The first thing we need to do is designate our service facade as a component.
@Service
public class MockWorldService implements WorldService {
  ..
}
This class is now eligible for detection during class path scanning, and Spring will automatically inject a MockWorldService object into any @Autowired field, method parameter or constructor parameter, which matches this type. For example.
@Autowired
private WorldService worldService;
So, if Spring autowires by type, what happens if there is more than one matching implementation? What happens when we add the live version of our service facade, which also implements WorldService?

Qualification

The @Qualifier annotation is used to identify a component by name.
@Autowired
@Qualifier(value = "mockWorldService")
private WorldService worldService;
The value element names the specific class type to be injected. In this case, the value is derived from the unqualified class name but, as an alternative, we could name the component explicitly, like this:
@Service(name = "dummyWorldService")
public class MockWorldService implements WorldService {
  ..
}
Now we specify dummyWorldService as the value in @Qualifier, rather than mockWorldService.

Tip
Tip - a different solution is to split the implementations into separate packages, and use different configuration files to perform the component scanning.

@Qualifier is an annotation rather than an element of @Autowired to allow methods or constructors to be annotated with @Autowired, and individual parameters to be annotated with @Qualifier.
@Autowired
public CountryForm(@Qualifier(value = "mockWorldService") WorldService worldService) {
  this.worldService = worldService;
}

Component Scanning

Finally, we alter the world-servlet.xml configuration file to scan the package which contains the service class. Let's just remind ourselves of the package structure in our application.

Application structure for Getting Started with Spring

We can include a second <context:component-scan> element like this:
<beans>

  <context:component-scan base-package="levelup.world.web"/>
  <context:component-scan base-package="levelup.world.domain.service"/>

  ..

</beans>
Or simply widen the seach by specifying a base-package which is a parent of all the required packages.
<beans>

  <context:component-scan base-package="levelup.world"/>

  ..

</beans>

Tip
Tip - Spring IoC Container Configuration, at the end of this section, isolates the configuration details for the service layer, by using a separate file.
»