Spring series, part 5: @Component vs @Bean
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