공부 이유
개발을 하다 보면 @Controller, @service, @Repository 어노테이션을 각 계층에 맞게 붙여서 사용하게 된다.
여러 교육을 받으면서 이 어노테이션이 무슨 차이를 가지고 있는지 설명을 들은 적이 없다.
그냥 Controller Class에는 @Controller 붙이고, Service Class에는 @Service 붙이라는 이야기를 듣고, 사용하기 급급했던 것 같다.
추후에 @RestController를 알게 되면서 @Controller와 @RestController의 차이를 개인적으로 공부하게 되었지만..
어노테이션 비교
각 어노테이션을 타고 어떻게 구성되어 있는지 한 번 알아보자
@Controller
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Service
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Repository
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
각 어노테이션에 붙어있는 메타 어노테이션(어노테이션에 붙이는 어노테이션)이 모두 동일한 것을 볼 수 있다.
심지어 어노테이션 내부에 구성되어 있는 로직 또한 완전하게 동일한 것을 확인할 수 있다.
즉, 이름만 다르고 똑같은 일을 하는 친구들이라는 것이다.
철수, 영희, 길동이 모두 이름은 다르지만 모두 스프링 빈으로 등록하여 사용될 수 있게 하는 역할을 맡고 있다.
그리고 스프링 부트 어플리케이션 어노테이션을 확인해 보자
@SpringBootApplication
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
@SpringBootApplication의 메타 어노테이션을 확인해 보면 @ComponentScan이 존재하는 것을 볼 수 있다.
스프링 부트가 실행되면서 등록된 Component들을 모두 Scan 하고, 그때 @Component를 메타 어노테이션으로 가지고 있는 @Controller, @Service, @Repository를 확인하게 된다.
결론
같은 역할을 하고 있지만 어노테이션의 이름을 다르게 구성하여 사용하는 이유는 뭘까?
어노테이션의 이름만으로, 이 어노테이션이 어느 계층에서, 어떤 역할을 하는 컴포넌트라는 것을 한눈에 알아볼 수 있기 때문이다.
내가 만약 나만의 계층을 만들어서, 역할을 구분하고 싶다면 똑같이 어노테이션을 제작하면 된다.
어떻게? 이렇게.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Component
public @interface ChordpliComponent {
@AliasFor(annotation = Component.class)
String value() default "";
}
번외
번외로 @RestController의 내부도 한 번 부검해 보자.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
...
@AliasFor(annotation = Controller.class)
String value() default "";
}
위의 어노테이션과 달라진 점이 있다면, @Componet 대신 메타 어노테이션으로 @Controller를 불러오고 있으며, @ResponseBody를 추가한 것을 볼 수 있다.
즉 Controller인데, ResponseBody를 곁들인 Controller라고 생각하면 된다.
결국 ResponseBody가 붙어있는, Component인 것이다.
'Server > Spring&Spring Boot' 카테고리의 다른 글
[Spring] Spotless + Pre Commit (0) | 2023.08.20 |
---|---|
[Spring Security] UserDetails를 User에 구현하여 사용하기. (0) | 2023.04.14 |
[Refactor] boolean을 사용하여 메서드 정리 (0) | 2023.04.01 |
[Spring] @Builder 사용시, 초기화해야할 필드가 존재할 때 발생하는 에러. @Builder will ignore the initializing expression entirely (0) | 2023.03.25 |
[Docs] Spring Rest Docs HTML 출력하는 법. (0) | 2023.03.22 |