본문 바로가기
Develop/Spring (이론)

Annotatoin 정리

by 보보트레인 2023. 6. 13.

어노테이션(@, annotation)이란?

사전적으로는 "주석"이라는 의미를 가지고 있으며, 자바 코드에 @를 이용해 주석처럼 달아 특수한 의미를 부여해준다.

프로그램 코드의 일부가 아닌 프로그램에 관한 데이터를 제공하고, 코드에 정보를 추가하는 정형화된 방법이다.

@SpringBootApplication

Spring Boot 를 자동으로 실행시켜주는 어노테이션으로 **[Bean](<https://www.notion.so/Bean-c099f22bc2f9410c98a14d3373c8be6b?pvs=21>) (클릭시 링크로 이동 )**

등록은 두 단계로 진행된다.

  1. @ComponentScan을 통해 Component들을 Bean으로 등록한다.
  2. @EnableAutoConfiguration을 통해 미리 정의해둔 자바 설정 파일들을 Bean으로 등록한다.

@ComponentScan 과 @Configuration은 아래에서 알아보자.

@ComponentScan

@ComponentScan 어노테이션과 @Component 어노테이션을 사용해서 빈을 등록하도록 하는 방법이다.

간단히 말하면 @ComponentScan 어노테이션은 어느 지점부터 컴포넌트를 찾으라고 알려주는 역할을 하고 @Component는 실제로 찾아서 빈으로 등록할 클래스를 의미한다.

Spring IoC 컨테이너가 IoC 컨테이너를 만들고 그 안에 빈을 등록할때 사용하는 인터페이스들을 라이프 사이클 콜백이라고 부른다.

라이프 사이클 콜백 중에는 @Component 애노테이션을 찾아서 이 애노테이션이 붙어있는 모든 클래스의 인스턴스를 생성해 빈으로 등록하는 작업을 수행하는 어노테이션 프로세서가 등록돼있다.

Spring Boot 프로젝트에서 @ComonentScan 어노테이션이 붙어있는 클래스가 이에 해당한다.

@ Configuration

@Configuration이라고 하면 설정파일을 만들기 위한 애노테이션 or Bean을 등록하기 위한 애노테이션이다.

@SuppressWarnings

노란 밑줄 예시이미지

위의 노란 표시를 지우는데 사용된다. 즉 경고를 지울 때 사용한다.

@SuppressWarnings("rawtypes")=> 하나만 적용할 경우

@SuppressWarnings({"rawtypes", "unchecked"})=> 두 개 이상 적용할 경우

아래의 내용 참조하여 넣어주면 된다.

all : 모든 경고

cast : 캐스트 연산자 관련 경고

dep-ann : 사용하지 말아야 할 주석 관련 경고

deprecation : 사용하지 말아야 할 메서드 관련 경고

fallthrough : switch문에서 break 누락 관련 경고

finally : 반환하지 않는 finally 블럭 관련 경고

null : null 분석 관련 경고

rawtypes : 제너릭을 사용하는 클래스 매개 변수가 불특정일 때의 경고

unchecked : 검증되지 않은 연산자 관련 경고

unused : 사용하지 않는 코드 관련 경고

@Autowired

필요한 의존 객체의 “타입"에 해당하는 빈을 찾아 주입한다.

  • 생성자 ( Constructor Dependency Injection )
  • setter ( Setter Dependency Injection )
  • 필드 ( Field Dependency Injection )

위의 3가지의 경우에 Autowired를 사용할 수 있다. 그리고 Autowired는 기본값이 true이기 때문에 의존성 주입을 할 대상을 찾지 못한다면 애플리케이션 구동에 실패한다. 그러면 Autowired를 사용할 때의 경우의 수가 존재하는데 각각의 상황에 대해서 정리해보자.

Constructor Dependency Injection

생성자 주입은 생성자에 의존성 주입을 받고자 하는 field를 나열하는 방법으로, 권고되는 방법의 하나 이다. 생성자 주입을 하면 좋은 이유에 대해서 자세히 알고 싶다면  여기에서 확인할 수 있습니다.

  • 장점
    • 필수적으로 사용해야 하는 레퍼런스 없이는 인스턴스를 만들지 못하도록 강제함
    • Spring 4.3 이상부터는 생성자가 하나인 경우 @Autowired를 사용하지 않아도 됨
    • Circular Dependency / 순환 참조2 의존성을 알아 차릴 수 있음
    • 생성자에 점차 많은 의존성이 추가 될 경우 리팩토링 시점을 감지 할 수 있음
    • 의존성 주입 대상 필드를 final로 불편 객체 선언할 수 있음
    • 테스트 코드 작성시 생성자를 통해 의존성 주입이 용이함
  • 단점
    • 어쩔 수 없는 순환 참조는 생성자 주입으로 해결하기 어려움
      • 이러한 경우에는 나머지 주입 방법 중에 하나를 사용
      • 가급적이면 순환 참조가 발생하지 않도록 하는 것이 더 중요

Setter Dependency Injection

setter 메소드에 @Autowired annotation을 선언하여 주입받는 방법이다.(메소드 이름을 setter 대신에 다른 걸로 하여도 주입은 가능하지만 좋은 방법은 아니다)

  • 장점
    • 의존성이 선택적으로 필요한 경우에 사용
    • 생성자에 모든 의존성을 기술하면 과도하게 복잡해질 수 있는 것을 선택적으로 나눠 주입 할 수 있게 부담을 덜어줌
    • 생성자 주입 방법과 Setter 주입 방법을 적절하게 상황에 맞게 분배하여 사용
  • 단점
    • 의존성 주입 대상 필드가 final 선언 불가

Field Dependency Injection

member field에 @Autowired annotation을 선언하여 주입받는 방법이다.

  • 장점
    • 가장 간단한 선언 방식
  • 단점
    • 의존 관계가 눈에 잘 보이지 않아 추상적이고, 이로 인해 의존성 관계가 과도하게 복잡해질 수 있음
      • 반대로 Constructor injection과 Setter injection은 의존성을 명확하게 커뮤니케이션 함
    • 이는 SRP / 단일 책임 원칙에 반하는 안티패턴
    • DI Container와 강한 결합을 가져 외부 사용이 용이하지 않음
      • 단위 테스트시 의존성 주입이 용이하지 않음
    • 의존성 주입 대상 필드가 final 선언 불가
    💡 예제로 알아보는 @Autowired의 편리함
    // Autowired 사용 전
    @Service
    public class BookService {
    
        private BookRepository bookRepository;
    
        public BookService(BookRepository bookRepository){
            this.bookRepository = bookRepository;
        }
    
    }
    
    //우선 BookService Class를 살펴보겠습니다. BookService Class는 생성자로 BookRepository
    //를 전달받고 인스턴스 변수에 할당하는 코드를 가지고 있습니다.
    
    <bean id="bookRepository" class="com.keesun.spring.BookRepository"/>
    
    <bean id="bookService" class="com.keesun.spring.BookService">
        <constructor-arg name="bookRepository" ref="bookRepository"/>
    </bean>
    
    //이때 원래의 경우라면 BookService에 Book Repository를 주입하기 위해서 XML파일에 다음과
    //같이 Bean 설정을 해주어야 했습니다.
    
    @Configuration
    public class ApplicationConfig {    
        @Bean
        public BookRepository bookRepository(){
            return new BookRepository();
        }
        
        @Bean
        public BookService bookService(){
            return new BookService(bookRepository());
        }    
    }
    
    //또는 위처럼 xml설정 파일을 대신하는 Java Class에 Bean설정을 만들어주어 해결할 수도 있습니다.
    
    

    @Service

    @Resource

  •  
반응형