만족은 하되 안주하지는 말자

기록해야 기억한다

프로그래밍/backend&devOps

[Spring] 어노테이션(annotation) 기반 bean 설정법

D36choi 2021. 6. 21. 15:39
728x90

어노테이션 기반 설정

AppConfig.java 파일을 이용한 스프링 컨테이너 빈 주입 방법은 관리해야하는 빈 수가 적은 경우에만 적절하다.

애플리케이션에 빈이 너무 많으면 불필요하게 작성해야하는 중복되는 코드들이 너무 많아진다.

그래서 스프링은 어노테이션 기반의 설정을 제공한다. 훨씬 쉽게 관리가 가능하다.

두 가지 유형의 어노테이션을 제공한다.

빈 선언 어노테이션

@Repository
@Controller
@Service
@Component

등의 스테레오 타입 어노테이션 세트를 제공한다. 스프링이 관리해야하는 클래스에 위 어노테이션을 적용한다.

스프링은 @ComponentScan 에 입력한 기본 패키지부터 스캔해서 위 어노테이션이 달린 클래스를 수집한다.

@Component 는 제네틱 스테레오 타입이다.

그 위의 3개 어노테이션은 DDD(도메인주도설계) 에서 사용된 용어를 나타낸다. 혹은 아래와 같이 구분된다.

@Service

DD Core J2EE 의 패턴인 비즈니스 서비스 facade(파사드) 를 나타낸다.

@Controller

전통 자바 EE 패턴인 DAO (Data Access Object) 를 나타낸다.

@Repository

HTTP Request 를 수신하는 웹 컨트롤러를 나타낸다.

즉 위 4개에 대해서 기능상 차이는 없고 제네릭타입을 계승해 계층 구분을 쉽게하려는 명시적인 의도로 구분하는 것이라고 난 이해하고 있다.

의존성 연결(혹은 주입) 어노테이션

@Required
@Autowired

@Required 는 setter 메서드, @Autowired는 생성자,메서드,필드에 적용가능하다.

두 어노테이션을 통해 스프링은 의존성이 필요한 객체에 선언되어있는 빈들을 주입 또는 연결을 할 수가 있게 된다.

연결 방법엔 3가지가 있다.


  1. 생성자 기반 주입
  2. 세터/메서드 기반 주입
  3. 필드 기반 주입

생성자 기반 주입

가장 권장되는 방법이다.

public class MemberServiceImpl implements MemberService {

    private final MemberRepository memberRepository;

    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

}

여기서 어노테이션 또한 생략이 가능하다. 스프링은 위 서비스 생성자를 검사하며 해당 인자의 빈을 연결시킨다.

세터/메서드 기반 주입

@Component
public class MemberServiceImpl implements MemberService {

    private final MemberRepository memberRepository;

    @Required
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

생성자를 제거하고 위처럼 할 수 있다. (@Autowired도 적용가능).

하지만 위 방식은 안쓰는게 낫다. 애초에 스프링5.1 에서 Deprecated(사후 지원안함) 되었기 때문이다.

굳이 스프링 개발자들이 버린 방식을 채택할 필요는 없지 않을까.

필드 기반 주입

@Autowired 로 필드에 직접 적용할 수 있다. 이방법을 통해 만들면 메서드 선언이 따로 필요없다.

@Component
public class MemberServiceImpl implements MemberService {
        @Autowired
    private MemberRepository memberRepository;

}

권장되는 것은?

반드시 필요한 의존성은 항상 생성자를 통해 주입해야 한다.

왜냐하면, 이 방식이면 필드 객체를 final로 지정가능하다. 즉, 최초 초기화된 이후에는 읽기 전용이 되어 함부로 수정할 수 없게 된다.

위에 보시다시피 필드기반 주입은 final 키워드를 field에 붙일 수 없다.

필수가 아닌 의존성은 메서드 기반의 주입을 하도록 하자.

필드 기반주입은 쓰지말아야 한다.

의존성을 초기화,관리 하는 방법과 이들의 의존관계와 같은 의존성 정보가 숨겨지게 된다.

또한 필드 주입 방식이 간단한만큼 처음 써보기 쉽지만 너무 많은 의존성을 추가하다보면 SRP 를 위반할 수도 있다.

그리고 순환참조의 문제가 생길 수 있다. 그건 다른 분들이 정리해놓은걸 나중에 살펴보도록 하자.