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
A very interesting article Tomas. Something that is worth mentioning is that the Repository annotation confers special behavior to all beans it marks. The PersistenceExceptionTranslationPostProcessor automatically applies persistence exception translation to any bean marked with @Repository. I have post more about this here: https://readlearncode.com/2016/02/13/insights-from-stackoverflow-most-voted-for-spring-4-questions/#1
ReplyDelete