Slight Difference between @RestController & @Component

Viewed 4093

Although every page on internet says that @RestController is a specification of @Component.I dont know whether it has to be related with DispatcherServlet. But when I try below code by switching between @RestController & @Component, I don't see same behaviour :

First I tried with @RestController:

@RestComponent
public class TestController {
    @RequestMapping(value="/testController", method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE)
    public void testController() {
        System.out.println("Hello");
    }

}

I got below output in Console:

Hello

Second I tried with @Component + @ResponseBody:

@Component
@ResponseBody
public class TestController {
    @RequestMapping(value="/testController", method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE)
    public void testController() {
        System.out.println("Hello");
    }
}

I got an error on postman:

{
    "timestamp": 1570998345860,
    "status": 405,
    "error": "Method Not Allowed",
    "message": "Request method 'POST' not supported",
    "path": "/testController"
}

If both annotations are same, then why is there a difference in output ??

Below is the Source code for @RestController & @Controller , which shows that both @RestController & @Controller are specification of @Component:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

}


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
}

Maybe it has to be related with DispatcherServlet. It might be possible that Dispatcher Servlet only check for URL in @RestController annotated classes.

4 Answers

@Controller is user in traditional controller and @RestController annotation was introduced to simplify the creation of RESTful web services. It's a convenience annotation that combines @Controller and @ResponseBody

@Controller annotation is simply a specialized of the @Component class and allows implementation classes to be autodetect through the classpath scanning.

@Controller is typically used in combination with a @RequestMapping annotation used on request handling methods.

The request handling method is annotated with @ResponseBody. This annotation enables automatic serialization of the return object into the HttpResponse.

@RestController is a specialized version of the controller. It includes the @Controller and @ResponseBody annotations and as a result, simplifies the controller implementation.

The controller is annotated with the @RestController annotation, therefore the @ResponseBody isn't required.

Every request handling method of the controller class automatically serializes return objects into HttpResponse.
see here in detail : https://www.baeldung.com/spring-controller-vs-restcontroller

Just because @RestController is a @Component does not mean you can achieve the same functionality by switching to the broader one @Component. Even with the addition of @ResponseBody, you don't achieve equivalent functionality (as expressed through the Request Method POST not being supported).

Replace @Component with @Controller, because a @RestController has the exact same functionality as a @Controller + @ResponseBody. You can also see this in the meta-annotations of @RestController, you see it is meta-annotated with @Controller instead of just @Component. In turn, @Controller is meta-annotated with @Component.

The @Controller , @RestController , @Service etc are all annotations that are meta-annotated with the @Component annotation. All these annotations are essentially specializations of the @Component annotation for specific use cases. The @Component annotation is generally used to register a Spring bean.

The @Controller annotation even though it is annotated with @Component internally , it provides a different functionality altogether.By annotating a class with this annotation we are essentially telling spring to scan this class for @RequestMapping annotation to register beans for request mapping. This does not happen when you just use the @Component annotation.

When the spring application starts up, the DispatcherServlet will enable the RequestMappingHandlerMapping RequestMappingHandlerAdapter (which is a handler mapping which looks for @RequestMapping annotations on @Controllers). So when a request reaches the dispatcher servlet it gives it to the RequestMappingHandlerMapping which resolves the uri to a controller method bean.For more information read : DispatcherServlet, Updated Doc Spring 5.x HandlerMapping

Note : In older versions of spring DefaultAnnotationHandlerMapping is enabled for this by spring.

So in summary :

  • @Component is a generic stereotype for any Spring-managed component or bean.
  • @Repository is a stereotype for the persistence layer.
  • @Service is a stereotype for the service layer.
  • @Controller is a stereotype for the presentation layer (spring-MVC).

Spring [Doc][4].

The @Controller annotation indicates that a particular class serves the role of a controller.

The basic purpose of the @Controller annotation is to act as a stereotype for the annotated class, indicating its role. The dispatcher will scan such annotated classes for mapped methods, detecting @RequestMapping annotations (see the next section).

Annotated controller beans may be defined explicitly, using a standard Spring bean definition in the dispatcher's context. However, the @Controller stereotype also allows for autodetection, aligned with Spring 2.5's general support for detecting component classes in the classpath and auto-registering bean definitions for them.

Similar post : What's the difference between @Component, @Repository & @Service annotations in Spring?

You should not get the same behaviour because @Component is more generic. It only registers your class as a Spring Managed Bean. However, @RestController not only registers your class as a managed bean, it further registers it as an entry point for HTTP calls to the specified URL path. Same goes for other Layer specific annotations like @Repository, @Configuration e.t.c

Related