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

박종수님의 프로필 이미지
박종수

작성한 질문수

스프링 핵심 원리 - 기본편

스프링으로 전환하기

getBean이 class를 받아야 하는 이유?

작성

·

961

7

안녕하세요. 명강의 듣다보니 궁금증이 생겨 질문 남깁니다.  getBean은 왜 인자로 클래스를 받는가? 입니다.

getBean의 역할은 객체를 넘겨주는 것이고 AppConfig에서 @Bean을 통해 constructor를 알려주었을 때 객체 생성을 위한 정보는 모두 받았다고 판단됩니다.

또한 getBean 앞뒤로 sout 찍어보니 실제로 getBean 이전에 모든 객체생성 로그가 찍히기에 궁금증이 더해졌습니다.

getBean의 역할을 수행하는데는 name만 가지고도 가능할텐데 왜 class를 인자로 받는걸까요??

워낙 명강의라 뒤에 나오는 내용을 궁금해하는중일지 모르겠습니다.ㅎㅎ

답변 1

3

안녕하세요 박종수님.

스프링과 JPA를 보면 인자로 문자열만 받는 경우와 문자열+타입을 받는 경우를 보실 수 있으신데요, 아래의 이미지를 봐볼까요?

,

위의 이미지는 "스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술"에서 JPA를 사용한 코드 인데요, 색깔별로 묶어서 보시면 되고 빨간색 박스는 쿼리에 해당하는 문자열만 입력하여 타입을 추론하지 못하고 .getResultList() 메서드를 사용하여 List인것은 명확하지만 Member타입 임을 선언하지 않아 List타입으로만 반환을 하는 것을 확인 하 실 수 있으시고,

주황색 박스는 파라미터 명에서도 나와있듯 <resultClass>를 명시해줬기 때문에 List<Member>가 반환 될 수 있는겁니다. 아래는 스프링에서의 동일 상황입니다.

,

빨간색 박스는 "memberService"라는 "이름"의 빈을 get하는 것이고 이것은 해당 빈의 타입을 뜻하는 것은 아닙니다. 그래서 모든 클래스의 조상인 Object를 반환하는 것은 어찌보면 당연한 것입니다.

반면 주황색 박스를 보시면 알 수 있듯 명확한 반환 타입을 지정하여 MemberService를 반환하는 것이구요.

,

제 설명이 미흡하거나 추가적으로 궁금한 점이 있으시면 댓글 남겨주세요. 감사합니다.

박종수님의 프로필 이미지
박종수
질문자

친절한 답변 감사합니다! @Bean의 어노테이션을 보고 컨스트럭터가 Bean에 등록될때 컨스트럭터의 반환형을 충분히 추론이 가능하지 않나? 싶어서 남긴 질문입니다.

예를 들어

System.out.println(AppConfig.class.getMethod("memberService").getReturnType());

를 해보면 

interface hello.core.member.MemberService

이 찍히는데 이런식으로 스프링이 Bean 등록과정에서 컨스트럭터만 보고 충분히 추론할 수 있지 않나.. 라는 생각이 들었습니다.

스프링이 getter, setter를 보고 변수명을 추론하듯이? 비슷하게 가능할거라 생각했던거 같네요ㅎㅎ

저런게 있었군요..

하나 배워갑니다 ㅎㅎ

종수님 말씀대로도 될것같으면서도 개발자에게 타입 명시를 맡긴것이 아닐까라는 생각이 드네요 ㅎㅎ

안녕하세요 박종수님!

.

getBean()을 호출할 때 파라미터로 String 만 전달할때는 반환값이 어떤 값이 될지 미리 예측할 수 없습니다. 그렇기에 getBean() 메서드는 아래와 같이 반환값을 Object로 설정할 수 밖에 없습니다. 반환값이 Object로 되어있다면 메서드 내에서 객체를 찾고, 그 객체의 타입을 추론해서 캐스팅을 한다해도 클라이언트는 결국 Object를 반환값으로 받기에 클라이언트가 다시 캐스팅을 해서 사용해야 합니다.

public Object getBean(String name) {
   ... 소스코드...
}

그러나 getBean()을 호출할 때 특정 클래스를 같이 파라미터로 넘기면 다음과 같은 코드가 됩니다.

public <T> T getBean(Class<T> requiredType) {
    ... 소스코드 ...
}

.

사용자가 파라미터로 넘긴 타입을 그대로 getBean()에서 반환해줄 수 있습니다. 그렇다면 클라이언트도 Object에서 캐스팅을 하지 않고 바로 사용할 수 있는 상태가 됩니다. 이런 편의를 위해 getBean() 메서드는 클래스를 받을 수 있도록 작성되었습니다.

.

감사합니다.

박종수님의 프로필 이미지
박종수
질문자

안녕하세요~
codesweaver님 말씀은 타입을 추정할 수는 있지만 클라이언트단에서 getBean()의 출력을 정확하게 예측할 수 없기 때문에 Object로 받은 후 캐스팅 해야 하기때문이라는 말씀으로 이해되는데 맞을까요??

안녕하세요!

클라이언트에서 이름(String)만으로 스프링컨테이너에 getBean()을 호출하였을때, 스프링 컨테이너 입장에서는 결과값으로 무엇을 반환하게 될 지 아직 알 수 없다는 의미입니다. 이름 가지고 객체를 찾아달라는데 어떤 객체가 찾아질지는 '찾아봐야 알 수 있습니다' 그래서 클라이언트가 찾는 객체가 뭐가 되었든 간에 일단 담을 수 있는 Object라는 큰 그릇에 담아서 반환하게 됩니다.

.

반면, 클라이언트가 클래스타입으로 스프링 컨테이너에 객체를 찾아달라고 요청한 경우 스프링 컨테이너는 클라이언트가 어떤 클래스타입을 필요로 하는지 명확하게 알게 됩니다. 그래서 클라이언트가 요청한 클래스타입 그대로 찾아서 반환해 줍니다.

.

정확히 같지는 않지만 예를 들면, 환자가 약국에 가서 '두통약' 주세요 라고 하면 약사는 두통약중 어떤걸 줘야 할지 명확히 알 수 없습니다. 그저 '두통약'인것 아무것이나 줄수밖에 없습니다. 그러나 환자가 '타이레놀' 주세요 라고 명확히 지명한 경우, 약사는 타이레놀을 줄 수 밖에 없습니다. 다른 두통약은 안되는 것이죠.

.

감사합니다.

박종수님의 프로필 이미지
박종수

작성한 질문수

질문하기