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.");  
   }  
}  
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 {   
  ..   
 }   
 // 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;  
 ..  
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