인프런 커뮤니티 질문&답변

권정익님의 프로필 이미지
권정익

작성한 질문수

스프링 핵심 원리 - 기본편

섹션 7. 옵션처리

해결된 질문

작성

·

119

·

수정됨

0

@Component
class Ex1 {
    private final Member member;

    @Autowired(request = false)
    public Ex1(Member member) {
        this.mamber = member;
    }
}

@Aurowired(request = false)를 사용하면 생성자 호출이 되지 않으니까

->Ex1은 스프링 빈으로 아예 등록 조차 안 되는 게 맞는 건가요?

 

@Nullable
Optional<Member>

만약 request = false를 사용하지않고,

Nullable과 Optional을 사용하면 Ex1은 스프링 빈으로 등록되는 게 맞나요??

 


그리고 수정자 주입같은 경우는

@Component
class Ex1 {
    private final Member member;

    @Autowired
    public void setEx1(Member member) {
        this.mamber = member;
    }
}

member가 스프링 빈에 등록되어 있지 않으면 Ex1을 스프링 빈에 member가 주입되지 않은 상태로 저장하고,

member가 스프링 빈에 등록되어면 그때서야 Ex1에 자동으로 주입을 해주는 게 맞나요?

 

답변 1

1

안녕하세요. 권정익님, 공식 서포터즈 OMG입니다.

->Ex1은 스프링 빈으로 아예 등록 조차 안 되는 게 맞는 건가요?

: Ex1은 @Component로 인해 스프링 빈으로 등록됩니다. 다만, @Autowired는 Ex1의 멤버변수인 member의 객체를 주입하지 못하는 것입니다.

또한 @Nullable과 Optional을 사용하면 member가 주입되지 않더라도 Ex1은 스프링 빈으로 등록됩니다.

 

수정자 주입의 경우 member가 스프링 빈으로 등록되어 있지 않으면 member는 주입되지 않지만 Ex1은 스프링 빈으로 등록됩니다. 나중에 member가 등록되더라도 자동 주입은 되지 않습니다.

감사합니다.

권정익님의 프로필 이미지
권정익
질문자

Ex1에 멤버변수 member은 final인데 생성자 호출이 안 되면 Ex1도 생성되지 못하는 거 아닌가요??

수정자 주입도 위에서 말한 것과 같은 맥락입니다...

final 변수에 초기화가 안 되니 Ex1은 스프링 빈에 등록되지 않아야 하는 게 아닌가요??ㅠㅠ

 

 

 

 

제가 질문을 잘못 파악했었네요. 혼선이 있었습니다. 다음 설명으로 이해하시면 될 것 같아요.

 

우선 아래 영한님 말씀처럼 생성자주입의 @Autowired(required=false)는 적용되지 않습니다.

https://www.inflearn.com/questions/214902

 

@Autowired(required=false)는 적용되지 않고 (required=true만 적용되므로) member를 생성자주입으로 받는 상황이 되니 궁금증이 풀리실 것 같습니다.

수정자 주입의 경우도 member 변수에 final 키워드를 적용한다면 객체의 생성이 컴파일 시점에 강제 되니

(생성자를 통해 인스턴스 주입이 필요한 것은 "생성자 주입을 선택해라!" 를 참고)

궁금하신 상황과도 연결되어 이해가 되실 것 같은데, 이해가 안가는 부분은 댓글 남겨주세요.

 

권정익님의 프로필 이미지
권정익
질문자

여러번 답변해주셔서 정말 감사드립니다!!

하지만.... 아직 헷갈리는 상태라 추가질문 해도 될까요!!

ApplicationContext ac =
    new AnnotationConfigApplicationContext(AutoAppConfig.class);

를 선언과 생성하면 AutoAppConfig에 있는 ComponentScan이 Component가 붙은
Ex1을 스프링 빈에 등록하려고 할 것입니다.

스프링 컨테이너는 객체 생성 / 의존관계 주입을 하게 됩니다.
그렇다면, 여기서 의문점이 생겼습니다.
1, Ex1의 멤버변수 member는 final로 선언 되어있다.
2, final로 선언되어 있으면 반드시 생성과 동시에 초기화를 해야한다.
3, 초기화 하지 않으면 컴파일 오류 발생.
 
이제 여기서 3가지로 갈라집니다.
@Autowired(request = false) -> 생성자를 호출하지 않음.
@Nullable -> 주입될 매개변수에 null값을 넣음.
@optional -> 주입될 매개변수에 Optional.empty값을 넣음.

@Nullable 과
@optional 은 그래도 null, Optional.empty라는 값을 넣음.
Ex1의 멤버변수 member은 초기화가 가능
따라서 Ex1의 객체 생성 가능 -> Ex1은 스프링 빈에 등록 가능.

여기서 의문은 끝에 다다랐습니다.
4, Ex1을 스프링 빈에 등록하려 할 때, 객체를 생성/ 의존관계 주입을 해야하는데
@Autowired(request = false)가 붙어있습니다.
5, 그렇다면 스프링 컨테이너는 의존관계 자동 주입을 하지 않을 것입니다.
왜냐하면 생성자를 호출 하지 않기 때문입니다.
6, 결국, Ex1의 멤버변수 member는 초기화 되지 못했습니다.
7, 따라서 Ex1의 객체는 생성될 수 없다.
라고 생각했습니다.
8, 최종적으로 Ex1은 스프링 빈에 등록 되지 않는다.

제가 생각한 게 맞는 건가요...??ㅠㅠ 

최대한 제가 궁금한 부분과 결과적으로 알고싶은 부분을 흐름대로 정리해봤습니다!!

4, Ex1을 스프링 빈에 등록하려 할 때, 객체를 생성/ 의존관계 주입을 해야하는데 @Autowired(request = false)가 붙어있습니다.

5, 그렇다면 스프링 컨테이너는 의존관계 자동 주입을 하지 않을 것입니다.

4번의 request (=요청) 이 아닌 required(=반드시 필요한, 필수적인)인데요

 

required가 true일 때는 반드시 필요하다는 속성이고

required가 false일 때는 있어도 그만 없어도 그만인 경우 많습니다.

참고로 스프링 MVC에서 배우는 @RequestParam(required) 속성도 마찬가지입니다.

 

'그래서 5번의 의존관계를 주입하지 않을 것이다' 라는 설명은 현재 답변과 이전 답변을 참고하여 다시 한번 고민해보셨으면 좋겠습니다.

 

그리고

왜냐하면 생성자를 호출 하지 않기 때문입니다.

이 단정의 설명은 아래의 코드 예시로 생성자를 호출하는지 확인해보시면 될 것 같습니다.

 

아무래도 머릿속으로 생각하는 것보다 실제 돌아가는 코드로 검증을 해서 결과를 눈으로 보면 이해에 도움이 되실 것 같아 코드로 작성해보았습니다. 각 코드를 이해하는건 어렵지 않으실거에요. 설명하신 내용과 실행 여부를 확인하기 위해 출력문을 추가해놓았습니다.

 

@ComponentScan
public class AutoAppConfig {
}
@Component
public class Ex1 {
    private final Member member;

    @Autowired(required = false)
    public Ex1(Member member) {
        System.out.println("생성자 호출");
        this.member = member;
    }

    public Member getMember() {
        System.out.println("Ex1.Member");
        return this.member;
    }
}
@Component
public class Member {
}

그리고 마지막으로 테스트 코드인데요.

 

테스트코드

class Ex1Test {
    @Test
    void test() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);

        Ex1 ex1 = ac.getBean(Ex1.class);
        Member member = ex1.getMember();

        Assertions.assertThat(member).isNotNull();
    }
}

(1) '생성자는 호출하지 않을 것이다' 라는 설명에 대해 실행결과의 콘솔 출력문을 보면 생성자가 호출되는 것을 볼 수 있습니다.

(2-1) 'Ex1의 멤버변수 member는 초기화 되지 못했습니다.' 'Ex1의 객체는 생성될 수 없다.' 라는 설명에 대해서도 의존주입을 받은 member를 Ex1클래스에서 getMember()로 반환하도록 하였고, 이를 테스트 코드에서 NotNull인지 체크하여 의존관계도 주입받은 것을 볼 수 있었습니다.

 

테스트 실행결과

image

직접 샘플코드를 실행해보시면서 관련하여 추가로 궁금한 사항은 댓글 남겨주세요.

권정익님의 프로필 이미지
권정익

작성한 질문수

질문하기