Spring

@Controller, @Service 의 차이? (@Aliasfor)

방금시작한사람 2020. 7. 1. 18:55

@Controller 와 @Service 의 차이는 무엇일까?

 

스프링 부트에서 어노테이션으로 @Controller 와 @Service가 붙는다.

 

차이는 ..?

 

어노테이션의 소스를 보면 이름만 다르고 코드는 똑같다.

그래서 service 에 controller 붙여도 되긴 된다. 

 

Service 어노테이션

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
	@AliasFor(annotation = Component.class)
	String value() default "";
}

 

Controller 어노테이션

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
	@AliasFor(annotation = Component.class)
	String value() default "";

}

 

둘다 코드는 똑같다. 이름만 다를 뿐

 

@AliasFor 은 3가지 사용예제가 있는 아래 나와있다.
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AliasFor.html#attribute--

 

 

※ 아래 2, 3은 해석을 했지만, 해석하는데 부족함을 느껴 정확한 정보를 위해 원문을 삽입합니다.

 

1) Explicit aliases within an annotation

        한 어노테이션에서 가명(별명)을 만든다. 

2) Explicit alias for attribute in meta-annotation

if the annotation() attribute of @AliasFor is set to a different annotation than the one that declares it, the attribute() is interpreted as an alias for an attribute in a meta-annotation (i.e., an explicit meta-annotation attribute override). This enables fine-grained control over exactly which attributes are overridden within an annotation hierarchy. In fact, with @AliasFor it is even possible to declare an alias for the value attribute of a meta-annotation.

 

@Aliasfor 의 annotation 의 속성값이 선언된 어노테이션과 다르면, attribute 값은 메타어노테이션의 속성의 별칭이라고 해석된다. (메타 어노테이션 속성의 명시적 오버라이딩) 어노테이션 계층에서 오버라이드된 속성들을 세밀하게 제어할 수 있게 된다. 사실, @AliasFor은 메타 어노베이션의 값 속성에 대한 별명까지 선언할 수 있다.

(여기서 메타어노테이션은 @Aliasfor 의 annotation 으로 들어가 값처럼 보입니다)

 

public @interface ParentAnnotation {
    String value() default="";
}

@ParentAnnotation
public @interface ChildAnnotation {

    @Aliasfor(annotation=ParentAnnotation.class, attribute="value")
    String aliasValue() default=""; // 재정의
    
    @Aliasfor(annotation=ParentAnnotation.class) //attribute 가 없으면 정의한 값과 똑같은것 가져오는 듯(?)
    String value() default="";
}

 

 

3) Implicit aliases within an annotation

if one or more attributes within an annotation are declared as attribute overrides for the same meta-annotation attribute (either directly or transitively), those attributes will be treated as a set of implicit aliases for each other, resulting in behavior analogous to that for explicit aliases within an annotation.

 

하나 또는 여러개의 속성이 같은 메타 어노테이션의 속성을 오버라이드 하면, 이 속성들은 각각 암시적 별명으로 여겨지며, 명시적 별명과 유사한 결과를 가져온다.

 

public @interface ParentAnnotation {
    String value() default="";
}

@ParentAnnotation
public @interface ChildAnnotation {

    @Aliasfor(annotation=ParentAnnotation.class, attribute="value")
    String aliasValue() default=""; 
    
    @Aliasfor(annotation=ParentAnnotation.class, attribute="value")
    String somethingValue() default="";
    
    @Aliasfor(annotation=ParentAnnotation.class, attribute="value")
    String something2Value() default="";
    
    // aliasValue, somethingValue, something2Value 는 같다
}

 

 

 

첫번째 예제는 RequestMapping 에서 찾을 수 있다. (불필요한 코드는 제외)

 

 path 와 value 를 같은 것으로 취급한다.

public @interface RequestMapping {
    @AliasFor("path")
    String[] value() default {};
    
    @AliasFor("value")
    String[] path() default {};
}

그래서 path 를 쓰건, value 를 쓰건 같게 동작한다.

 

 

public class SomeController() {
    @RequestMapping(path="/path/something")
    //@RequestMapping("/path/something")
    //@RequestMapping(value="/path/something")
    public SomeResponseDto doSomething() {
    
    }
}

It is permissible to omit the element name and equals sign (=) in a single-element annotation whose element name is 'value'.

 

https://docs.oracle.com/javase/7/docs/technotes/guides/language/annotations.html

 

value가 생략이 가능한 이유는 어노테이션의 value는이름과 '=' 를 생략할 수 있다고 한다. (value 인자만 있을 경우)

@RequestMapping(method=~, "/path/something") 는 생략할 수 없다. 

 

 

두번째 예제는 GetMapping 에서 볼 수 있다.

@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {

	/**
	 * Alias for {@link RequestMapping#name}.
	 */
	@AliasFor(annotation = RequestMapping.class)
	String name() default "";

	/**
	 * Alias for {@link RequestMapping#value}.
	 */
	@AliasFor(annotation = RequestMapping.class)
	String[] value() default {};
    
	...
}

 

 

 

 

..

 

세번째는 .. 찾을수가 없엇다 ㅎㅎ;

 


 

 

어쨌든 @Component와 같은 역할을 한다는것이다. 

 

그럼 왜 각각 다른 이름으로 구분해놨을까?

 

@Component / strategy 패턴