In this post, I will look into the distinction between a component and a bean. Even though both of them refer to Spring managed beans, each serves a different purpose. @Component and its specializations (@Controller, @Service and @Repository) allow for auto-detection using classpath scanning. @Bean on the other hand can only be used to explicitly declare a single bean in a configuration class.
You might find interesting that components have been around for quite a long time, since Spring 2.5. Here is a brief overview of the component types and their purpose. As you will see in a short while, all component types are treated in the same way. The subtypes are mere markers, think code readability rather than features.
Component types and their purpose
Annotation | Purpose |
@Component | A candidate for auto-detection via classpath scanning. |
@Controller | A web controller, popularized by Spring MVC. |
@Repository | Data manager / storage, ties to enterprise apps (DAO, DDD) |
@Service | Meant to provide business logic - a (stateless) facade. |
I said there is no difference among the individual component types. Let's prove it using a simple web app which exposes a single url returning a message in a JSON format. The front-end is, naturally, handled by a controller:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.zezutom.springseries0114.part04.model.Message;
@Controller
@RequestMapping("/web/message")
public class WebController {
@RequestMapping(method = RequestMethod.GET)
public @ResponseBody
Message message() {
return new Message("Controller", "An old good controller.");
}
}
However, any @Component would do, as shown on the following "controllers". As long as it can be found on the classpath, it is good to use:
import org.springframework.stereotype.Component;
..
@Component // Not a controller?! Makes no difference
@RequestMapping("/component/message")
public class ComponentController {
..
}
import org.springframework.stereotype.Service;
..
@Service // Not a controller?! Makes no difference
@RequestMapping("/service/message")
public class ServiceController {
..
}
Now, a bean right? That's a slightly different story. A @Bean-annotated class would not be found and could not be therefore used as a controller in the example above. Though, auto-wiring definitely applies here and provided the bean is defined in either an xml or a programmatic configuration it can be easily dependency-injected. Let's promote code reusability and enhance our controllers with a dedicated message builder:
// Just a POJO
public class MessageBuilder {
public Message getInstance(String title, String text) {
return new Message(title, text);
}
}
// Let's turn the POJO into a bean
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
..
@Configuration
public class AppConfig {
@Bean
public MessageBuilder messageBuilder() {
return new MessageBuilder();
}
}
// Finally, hook it up
..
@Autowired
private MessageBuilder messageBuilder;
..
The example is obviously fully covered by tests, feel free to download the source code and try it out.
Source Code
Previous: Part 4 - @Lazy on injection points
Next: Part 6 - Spring 4 and generics-based injection matching