2020-3-20 스프링 어노테이션 이해하기

배경

  • 최근 java, spring을 다시 학습하고 있다. 예전에 학습했을때는 그냥 주먹구구식으로 코드 동작만 시켰지 원리에 대해 어떻게 사용하는지에 대한 이해가 부족했었다. 그 이유중 하나가 바로 @Service, @Transactional 등 어노테이션에 대한 이해가 안됬기때문이다. 이 부분을 차근차근 해결하고자 한다.

문제 : @Scope가 뭐에요??

@Component
@Scope(scopeName = "jimmyScope",value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Proto {
}
  • 저 코드만 봐서는 정확하게 @Scope가 어떤 동작들이 이루어지는지 알기 어려웠다.
  • @Scope가 있는데 안에있는 scopeName, value, proxyMode는 어디서 가져오며 어떤것일까? 라는 궁금증이 있어서 Scope.java파일을 들어가 봤다. 아래와 같은 코드들이 있었는데, 더 멘붕이였다.
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {

	/**
	 * Alias for {@link #scopeName}.
	 * @see #scopeName
	 */
	@AliasFor("scopeName")
	String value() default "";

	/**
	 * Specifies the name of the scope to use for the annotated component/bean.
	 * <p>Defaults to an empty string ({@code ""}) which implies
	 * {@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
	 * @since 4.2
	 * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
	 * @see ConfigurableBeanFactory#SCOPE_SINGLETON
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
	 * @see #value
	 */
	@AliasFor("value")
	String scopeName() default "";

	/**
	 * Specifies whether a component should be configured as a scoped proxy
	 * and if so, whether the proxy should be interface-based or subclass-based.
	 * <p>Defaults to {@link ScopedProxyMode#DEFAULT}, which typically indicates
	 * that no scoped proxy should be created unless a different default
	 * has been configured at the component-scan instruction level.
	 * <p>Analogous to {@code <aop:scoped-proxy/>} support in Spring XML.
	 * @see ScopedProxyMode
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;

}
  • 이 문서를 어떻게 해석을 하고 이해를 해야되는가?

    1. 저 인터페이스 내부에 있는 메서드들을 직관적으로 이해하기로 했다. Scope라는 인터페이스에 value(), scopeName, proxyMode()라는 메서드가 정의되어 있고 각각의 default값이 있다.
    2. @Scope()안에있는 프로퍼티들은 Scope 인터페이스에 정의된 메서드들을 호출하는것이고 그 메서드를 호출하기 위해서 @AliasFor(“alias”)를 @Scope(alias=”value”) 불러서 사용을 하면된다.
  • 내가 궁금한것들 @AliasFor, @Documented, @Retention, @Target… 어노테이션이 끝도 없다. 결국 내가 이해해야되는것은 자바의 어노테이션을 이해해야된다.

어노테이션 이해하기

  1. 컴파일러에 정보를 가르쳐준다.
  2. 컴파일할 때, 설치할때 작업을 지정
  3. 실행할때 별도의 처리가 필요할때
  • 어노테이션은 위의 3가지 경우에 사용한다.
  • 자바언어에서 사용되는 어노테이션은 3가지(@Override, @Deprecated, @SupressWarning)이고 어노테이션을 선언하기 위한 메타 어노테이션이 4개(@Target, @Retention, @Documented, @Inherited)가 있다.
  • @interface : 커스텀 어노테이션을 만들때 사용한다. 대부분의 스프링 어노테이션들이 여기에 해당한다.

@Target

  • 어디에 어노테이션을 적용하면 좋을지 선언할때 사용한다.
@Target(Elementtype.METHOD)
@Target({ElementType.TYPE, ElementType.METHOD})
ELEMENTTYPE
  - CONSTRUCTOR
  - FIELD
  - LOCAL_VARIABLE
  - METHOD
  - PACKAGE
  - PARAMETER
  - TYPE : 클래스, 인터페이스, enum 
  • 예를들어 위의 코드처럼 @Target(Elementtype.METHOD)로 선언을 하면 이 어노테이션은 메서드 위에 선언을 할 수 있는것이다. @Transactional어노테이션처럼. Elementtype.TYPE으로 선언하면 @Controller, @Service와 같이 클래스를 선언할때 쓸 수 있다.

@Retention

  • 얼마나 오래 어노테이션 정보가 유지되는지 선언
@Retention(RetentionPolicy.RUNTIME)

ReteionPolicy
  - RUNTIME : 실행시 JVM에서 참조가능
  - SOURCE : 컴파일시 정보가 사라짐
  - CLASS : 컴파일러에 의해 참조가능. JVM에서는 사라짐

@Documented, @Inherited

  • @Documented는 해당정보가 Javadocs에 포함된다.
  • @Inherited는 모든 자식클래스에서 부모클래스의 어노테이션을 사용가능

결론 : @Scope 이해하기

  • 위의 어노테이션 메서드들을 보니 @Scope의 원리를 이해할 수 있다.
  • @Scope의 @Target은 Type, METHOD로 선언되어있다. @Scope는 메서드의 위나 클래스, 인터페이스, ENUM에서 사용할 수 있다.
  • @Retention의 RetentionPolicy는 Runtime으로 JVM에 의해 참조가능하다.
  • @Documented는 자바 공식문서에 이 스펙이 정의되어있다.
  • 각 메서드에는 @AliasFor(“aliasName”)가 선언이 되어있다. 이 내용은 @Scope(aliasName=”value”)로 사용가능하다.

느낀점

  • 스프링을 학습할때마다 자바문법이나 내부적으로 정의되어있는 어노테이션들 동작원리 등에 대해서 이해하는 것이 어려웠다. 오늘 이 부분을 해결하고자 자바의 커스텀어노테이션만들기을 학습하고 스프링 내부적으로 선언되어있는 어노테이션들을 차근차근 봤다. 시간은 좀 더 걸리지만 천천히 원리를 이해하면서 학습을 하니 이해가 더 잘됬다. 앞으로 자바, 스프링의 기술문서를 보고 이해하는데 많은 도움이 될거같다.

Reference

  • https://stackoverflow.com/questions/9921676/what-does-class-mean-in-java
  • 자바의신 17장
  • https://www.inflearn.com/course/spring-framework_core/lecture/15511 => 인프런 스프링 프레임워크 핵심 기술 참조
Written on March 20, 2020