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

snowdrop6342님의 프로필 이미지
snowdrop6342

작성한 질문수

스프링 핵심 원리 - 기본편

전체 흐름 정리

AppConfig에서 생성자로 주입되는 원리

작성

·

516

4

안녕하세요. 비전공자 백엔드 개발자 준비중입니다.

강사님 좋은 강의 덕분에 spring 공부에 큰 도움이 되고 있습니다.

AppConfig에서 역할과 구현을 나누어 구현체를 쉽게 바꿀 수 있다는 원리는 이해하였습니다.

여기서 제가 궁금한게 어떻게 AppConfig에서 메소드를 만들어 구현체를 넣어주면 생성자를 통해 받을 수 있는지, 그 원리가 궁금합니다.

생성자에서 this.객체 = 객체 이런식으로 받는데, AppConfig에서 넣어준 값이 어떻게 해서 이런 원리로 주입이 되는건가요? 제가 생성자 개념이 부족해서 이해가 안되는 것 같기도 하네요...

그리고 Test에서는 AppConfig  인스턴스를 생성해서 넣어줬는데, 왜 실제로는 그렇게 해주지 않은건가요? 메모리 낭비 때문에 그런걸까요? 인스턴스 생성 해서 넣어주는 부분은 이해가 되는데, 생성자로 주입해주는 부분은 원리가 이해가 되질 않네요.

답변 8

7

김영한님의 프로필 이미지
김영한
지식공유자

제가 순서를 풀어서 설명을 드릴게요.

먼저 @Bean이 있으면 스프링이 스프링 빈으로 등록해야 하기 때문에 해당 메서드를 호출합니다.

1. memberService() 메서드가 호출됩니다.

2. return new MemberServiceImpl(memberRepository());

자바 언어에서는 가장 안쪽에 있는 메서드가 먼저 호출됩니다. 그래서 memberRepository() 메서드가 호출됩니다.

3. memberRepository() 메서드를 호출하면 다음 로직이 실행됩니다.

- return new MemoryMemberRepository();

4. new MemoryMemberRepository(); 객체가 생성되고, 생성된 인스턴스의 주소값이 x01이라고 하겠습니다.

- return x01; 이제 x01이 반환됩니다.

5. return new MemberServiceImpl(memberRepository()); 리턴이 와서 다음과 같이 변경됩니다.

-> return new MemberServiceImpl(x01);

6. return new MemberServiceImpl(x01);를 실행합니다. 생성자를 호출하면서 x01를 넘깁니다.

7. 다음 로직을 치환해보겠습니다.

private final MemberRepository memberRepository;

public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
private final MemberRepository memberRepository = x01;

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

8. return new MemberServiceImpl(x01);의 결과로 MemberServiceImpl 객체가 생성되었습니다. 이 객체는 x02라고 하겠습니다.

9. return x02;가 됩니다.

감사합니다.

4

snowdrop6342님의 프로필 이미지
snowdrop6342
질문자

제가 궁금했던 부분이 정확히 해소됐습니다!

구체적으로 물어봐주시고, 꼼꼼하게 설명해주셔서 정말 감사합니다!!

3

snowdrop6342님의 프로필 이미지
snowdrop6342
질문자

네, 실무 위주로만 급하게 배우다보니 기초를 많이 놓친 것 같다는 생각이 들었습니다.

강사님 말씀대로 자바 책 한 권 정독해보도록 하겠습니다. 감사합니다!  

1

김영한님의 프로필 이미지
김영한
지식공유자

네^^

사실 이 부분이 이해가 어려운 것은 자바 기초가 약해서 그렇습니다.

자바 기초 책을 한권 완전히 정복하시길 추천드립니다.

그리고 이 부분을 다른 순수 자바 코드로 하나 만들어서 그림을 그리면서 정리하시면 좋을 것 같아요.

감사합니다.

1

snowdrop6342님의 프로필 이미지
snowdrop6342
질문자

1번 질문만 더 구체적으로 질문을 다르게 해보겠습니다.

제가 궁금했던 부분은 강사님이 답변해주신 부분 이후에 어떻게 생성자를 통해 그 값이 MemberServiceImpl 지역변수인 memberRepository에 전달이 되는 과정이 궁금했습니다.

AppConfig에서 

@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}

위와 같이 역할에 구현체 관계를 만들어주었습니다.

그러면, MemberService interface가 실행이되면서, MemberServiceImpl(memberRepository())가 return이 되고, memberRepository()가 실행되면서, memoryMemberRepository가 return이 되게되어 memberRepository의 객체에는 memoryMemberRepository가 들어있는 상태에서

private final MemberRepository memberRepository;

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

생성자 MemberServiceImpl이 실행되면서, 매개변수에 memberRepository가 들어가는데, 이 때, memberRepository에는 memoryMemberRepsitory가 들어있기 때문에 this.memberRepository = memberRepository(memoryMemberRepsitory값이 들어있음)을 통해 지역변수인 memberRepository에 memoryMemberRepository의 값이 들어가는 원리로 볼 수 있을까요?

위의 과정은 제가 생각해본 생성자를 통해서 지역변수 memberRepository 객체에 구현체가 들어가는 과정을 풀어낸 것입니다. 이 과정으로 구현이 되는 것이 맞는지 확인해주시면 감사하겠습니다.

항상 친절한 답변 감사드립니다!

1

김영한님의 프로필 이미지
김영한
지식공유자

첫번째 질문의 답은 다음 코드에 있습니다.

@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}

여기에 보면 new MemberServiceImpl을 하면서 memberRepository()를 호출합니다. memberRepository()의 호출 결과가 결국 new MemoryMemberRepository()가 되겠지요.

설명을 위해서 코드를 풀어보면 다음과 같이 됩니다.

1. return new MemberServiceImpl(memberRepository())

먼저 memberRepository()가 호출됩니다. 그러면 풀어서 설명드리면 memberRepository()의 결과로 생성된 memtoryMemberRepository 인스턴스가 반환됩니다.

2. return new MemberServiceImpl(new MemoryMemberRepository()); //쉽게 설명하기 위해서 풀어서 설명

첫번째 질문을 제가 정확한 답변을 드리기 위해 여러번 읽어보았는데, 정확하게 이해를 못 했을 수도 있습니다. 그러면 보충 설명을 부탁드릴게요.

두번째 질문은 제가 여러번 읽어보았는데, 이해를 잘 못했습니다. 첫번째 질문과 같은 질문이 것 같기도 하구요. 예제 코드를 최대한 많이 활용해서 풀어서 다시 설명해주시면 좋을 것 같아요.

감사합니다.

1

snowdrop6342님의 프로필 이미지
snowdrop6342
질문자

첫 번째 질문입니다.

AppConfig class에서

@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}

@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}

다음과 같이 memberService(), memberRepository() 메소드를 만들어 구현체를 return해주었습니다.

private final MemberRepository memberRepository;

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

이후, memberServiceImpl class에서 memberRepository의 객체를 생성자를 통해 주입시켜 주었습니다.

여기서 궁금한 점이, memberServiceImpl class에서 AppConfig를 따로 import하지도 않고, 인스턴스를 생성해서 AppConfig의 메소드를 불러와 값을 넣어주지도 않았는데, 어떤 원리로 생성자를 통해 AppConfig에서 구현체를 return해준 메소드들이 실현이 되었는지가 궁금합니다.

제가 아는 지식으로는 보통 메서드를 실행하려면, 메서드가 포함된 class를 import 후, 인스턴스를 생성하고, AppConfig.memberRepository()와 같이 실행 문법을 적용해줘야할텐데요. memberServiceImpl에서는 따로 AppConfig를 import하지도,  AppConfig.memberRepository()와 같이  메서드를 실행하는 문법을 적용시켜주지도 않았습니다. 그런데 어떻게 AppConfig에서 관계를 설정한 것이 생성자를 통해서 구현됐는지가 궁금합니다.

두 번째 질문입니다.

MemberService memberService;

@BeforeEach //test 실행하기 전 실행
public void beforeEach() {
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
}

테스트에서는 위와같이 AppConfig의 인스턴스를 생성하여 메소드를 넣어주는 식으로 구현했습니다. 하지만, 실제로는 첫 번째 질문에서와 같이 AppConfig의 인스턴스가 아닌 생성자를 통해서 객체를 주입시켜주는 원리로 해주셨다고 하셨습니다. 실제로는 왜 인스턴스로 넣어주는 것이 아닌 생성자를 통해서 넣어준것인지가 궁금합니다.

[영상]

관심사의 분리 6분40초~7분50초: AppConfig에서 설정한 관계 메소드를 생성자를 통해 구현하는 부분

-> 7분15초쯤 부터 AppConfig를 통해 memberService를 불러다 쓰면,  memberServiceimpl이 생성이되고, 구현체가 AppConfig에서 들어간다고 말씀하셨는데, 제가 궁금한 부분이 생성자를 통해서 AppConfig의 memberService()가 어떻게 호출되는지가 궁금합니다.

관심사의 분리 24분~24분50초: Test에서 AppConfig 인스턴스 객체 생성 후, 생성한 인스턴스 메서드를 통해 Service의 구현체를 넣어주는 부분

-> 실제 구현에서는 생성자를 통해서 구현했는데,  왜 Test에서는 AppConfig 인스턴스 객체 생성 후 구현했는지 궁금합니다.

Test 부분에서 구현한 원리가 제가 생각하고 있는 구현원리인데,  실제 생성자를 통해서 객체를 주입한 부분은 어떤 원리로 돌아가는지 모르겠네요.

최대한 제가 모르는 부분을 나름 표현해서 적긴했는데요. 제가 기초적인 지식이 부족해서 그런가 전달이 어렵나봅니다. 

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. snowdrop6342님

도움을 드리고 싶은데, 질문을 좀 더 자세히 보강해주시면 좋겠습니다^^

Q: 여기서 제가 궁금한게 어떻게 AppConfig에서 메소드를 만들어 구현체를 넣어주면 생성자를 통해 받을 수 있는지, 그 원리가 궁금합니다.

생성자에서 this.객체 = 객체 이런식으로 받는데, AppConfig에서 넣어준 값이 어떻게 해서 이런 원리로 주입이 되는건가요? 제가 생성자 개념이 부족해서 이해가 안되는 것 같기도 하네요...

-> 이 부분을 예제 코드로 모두 적고 궁금한 부분을 코드 단위로 설명해주시면 좋겠습니다.

Q: 그리고 Test에서는 AppConfig  인스턴스를 생성해서 넣어줬는데, 왜 실제로는 그렇게 해주지 않은건가요? 메모리 낭비 때문에 그런걸까요? 인스턴스 생성 해서 넣어주는 부분은 이해가 되는데, 생성자로 주입해주는 부분은 원리가 이해가 되질 않네요.

-> Test에서는 AppConfig  인스턴스를 생성해서 넣어줬는데 -> 혹시 이 부분이 강의 어떤 부분의 몇분 몇초인지요?

-> 왜 실제로는 그렇게 해주지 않은건가요? -> 이 부분도 강의 어떤 부분의 몇분 몇초인지요?

snowdrop6342님의 프로필 이미지
snowdrop6342

작성한 질문수

질문하기