Component, Repository, Service 애너테이션 중 무엇을 사용하더라도 Spring Bean에 등록되는 건 동일합니다.
그럼 어떤 차이가 있고, 둘을 구분해서 사용하는 기준은 무엇일까요?
1. 🔎 Component Scan
스프링은 설정된 범위를 탐지해 Spring Bean으로 생성해
Application Context에 보관합니다.
모든 클래스를 Spring Bean으로 생성해두는 것은 아니고,
그러하도록 선언된 클래스들을 생성합니다.
Spring Bean으로 생성하도록 선언하는 방법은 크게 세 가지가 있습니다.
XML 선언 방법은 이젠 잘 사용되지 않는 방법입니다.
@Configuration 클래스 내부에 @Bean 메서드로 선언하는 방법도 있습니다.
마지막으로 가장 많이 사용되는 클래스레벨 애너테이션을 사용하는 방법이 있습니다.
이렇게 Spring이 Spring Bean으로 생성하도록 선언된 클래스를 탐지하는 것을
Component Scanning 이라고 합니다.
기본 설정값은 @SpringBootApplication 애너테이션이 선언된 클래스의 하위 패키지입니다.
물론 이 설정 역시 별도 설정을 통해 커스터마이징할 수 있습니다.
2. 🧩 @Component
org.springframework.stereotype 패키지 내부입니다.
가장 자주 쓰이는 애너테이션들인 @Controller, @Service, @Repository 등이 있습니다.
그런데 그 애너테이션들 안으로 들어가면 모두 @Component 애너테이션을 확인할 수 있습니다.
애너테이션은 이미 만들어져 있는 다른 애너테이션을 조합하여 만들 수 있습니다.
Spring Bean으로 등록되게 선언해주는 역할은 @Component 애너테이션이 수행합니다.
@Component 애너테이션의 주석은 다음과 같이 작성되어 있습니다.
Indicates that an annotated class is a "component".
Such classes are considered as candidates for auto-detection
when using annotation-based configuration and classpath scanning.
Application Context에서 Spring Bean들을 생성하고 조립할 때,
사용될 수 있는 후보 클래스로 자동 탐지하도록 설정한다는 의미로 이해할 수 있겠습니다.
3. ⚙️ Component 애너테이션 내부 읽어보기
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
String value() default "";
}
ElementType은 enum으로, 해당 애너테이션이 선언될 수 있는 범위를 지정하는데 사용됩니다.
value로는 TYPE, FIELD, METHOD, PARAMETER 등이 있습니다.
가령 @Component 애너테이션은 @Target(ElementType.Type)으로 선언됐기 때문에,
클래스나 인터페이스, 다른 애너테이션이나 Enum에만 선언할 수 있습니다.
RetentionPolicy 역시 enum으로, 애너테이션의 유지 정책을 지정하는데 사용됩니다.
SOURCE, CLASS, RUNTIME 세 가지 value가 있습니다.
SOURCE는 compiler에 의해 애너테이션이 제거됨을 의미합니다.
CLASS는 class 파일까지만 유지되고 런타임에 제거됩니다. 기본값입니다.
RUNTIME은 class 파일에 유지되고 런타임에도 VM에 의해 유지됩니다.
@Documented 는 javadoc과 같은 도구에 애너테이션들을 표시할지 여부를 결정합니다.
A클래스에 @Documented 애너테이션을 달면,
A클래스에 대한 javadoc을 생성했을 때, A클래스에 있는 애너테이션들이 표시됩니다.
(로 해석했지만.. 확신이 들진 않네요 ^^;)
@Indexed 은...
이 애너테이션이 선언된 요소가 색인되어야 하는 스테레오 타입임을 나타낸다고 하는데..
사실 주석을 읽고 다른 자료를 찾아봐도 정확히 어떤 역할인지 이해하기 어려웠습니다 ^^;
혹시 아시는 분은 댓글 주시면 배워서 추가해보겠습니다!
문서 링크입니다
이제 다른 애너테이션을 읽을 수 있는 최소한의 눈이 생긴 것 같습니다!!
4. 🩻 Service 애너테이션 내부 읽어보기
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
@AliasFor(annotation = Component.class)
String value() default "";
}
주석의 설명은 다음과 같습니다.
- 이 클래스가 Domain-Driven Design(Evans, 2003) 에서 정의한 "Service"임을 나타냅니다.
- 캡슐화 없이 모델 안의 단독 인터페이스로서 제공되는 동작을 의미합니다.
- 비즈니스 서비스의 정면, 표면임을 나타내는데 사용될 수도 있습니다.
해석이 좀 어렵네요 ^^; 대략 다들 알고 있는 그 서비스를 말하는 것 같긴 합니다.
비즈니스 로직을 수행하는 레이어로서의 서비스 레이어 말입니다.
그런데 DDD가 언급되어 있어 놀랐네요. 와우.
아무래도 Spring Bean으로 생성되게 하면서도, 어떤 목적으로 등록되어야 하는지
개발자가 알아보기 쉽게 하기 위해 만들어진 것 같습니다. 추가적인 기능은 없어보입니다.
5. 📂 Repository 애너테이션 내부 읽어보기
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
@AliasFor(annotation = Component.class)
String value() default "";
}
주석의 설명은 다음과 같습니다.
- 이 클래스가 Domain-Driven Design(Evans, 2003)에서 정의한 "Repository"임을 나타냅니다.
- 객체를 담은 컬렉션에 대한 저장, 회수, 검색 등의 행위를 모방하여 동작하는 캡슐화된 저장공간을 의미합니다.
- 전통적 Java EE 패턴을 사용하는 팀은 Data Access Object 에 사용할 수 있습니다.
아주 친절하고 섬세하게 협업 시에 어떻게 적용해야 하는지 설명해주는 부분이 인상적이었네요.
6. ✨ Repository 애너테이션의 특별한 기능
Hibernate와 같은 영속성 프레임워크를 사용할 경우,
@Repository 애너테이션 이 선언된 클래스에서 발생하는 영속성 예외를
스프링의 org.springframework.dao.DataAccessException 의 서브클래스로 자동전환해준다고 합니다.
눈으로 좀 확인하고 싶어서 이래저래 시간을 썼는데,
영속성 프레임워크를 사용해야 할때 그렇다는 조건을 나중에야 봤네요 ;ㅅ;...
2022.04.24 추가
JDBC Template 의 사용법을 잘 알지 못해 여러 행이 결과로 와야 하는 상황에
queryForMap을 사용했었습니다. 해당 메서드는 결과 행이 2행 이상일 경우 Exception이 발생합니다.
이때 Exception이 스프링 프레임워크의 DataAccessException으로 생성됨을 확인했습니다.
그런데... @Componenet 애너테이션을 사용하고 있음에도 이쪽으로 와져서...
하... 잘 모르겠네요... ㅋㅋㅋㅋ 후... 엄청 중요한 건 아닌 것 같으면서도
공부한 내용과 다른 결과가 나오니 피곤하지만 넘어가겠습니다...
혹시 제가 놓친 부분을 알고 계시다면 꼭 제보 부탁드립니다 감사합니다.
7. ✅ 결론
Application Context에 등록시킬 클래스들을 선언하는 방법은
XML, @Bean, 클래스레벨 애너테이션 등이 있다.
Component Scan에 의해 자동 탐지 되기 위해 @Component 클래스레벨 애너테이션이 주로 사용된다
@Controller, @Service, @Repository 애너테이션도 내부에 @Component 애너테이션이 있다.
기능적 차이가 거의 없음에도 애너테이션을 구분해서 사용하는 것은
개발자간 소통, 레이어별 구분 등을 위함이다.
Repository 애너테이션은 일부 영속성 컨텍스트 사용시 영속성 예외를 자동 전환해준다.
음.. 이래저래 내용이 있었지만 결론은..
비즈니스 로직을 담은 서비스 레이어 라면 서비스 애너테이션을,
DB에 접근하는 객체라면 Repository 애너테이션을 사용하면 되겠군요. ㅋㅋㅋ
둘 다 빈 등록이 된다는 공통점이 있고 기능적 차이는 거의 없다고 봐도 될 것 같습니다.
학습 출처
https://www.baeldung.com/spring-component-repository-service
'우아한테크코스 4기' 카테고리의 다른 글
🆙 테스트 어려운 부분 끌어올리기 (feat. Spring 체스 게임방) (2) | 2022.05.15 |
---|---|
우당탕탕 Repository 제작기 (feat. Reflection) (2) | 2022.05.06 |
Spring 의존성 주입 방법 중 생성자 주입을 사용해야 하는 이유 (0) | 2022.04.22 |
Level 1을 정리하는 레벨 인터뷰 후기 (2) | 2022.04.22 |
다중 행 Insert 최적화 (Level 1 체스 미션 초기 체스판 구성) (2) | 2022.04.09 |