강의

멘토링

로드맵

Inflearn Community Q&A

lbd49464369's profile image
lbd49464369

asked

Spring Core Principles - Basic Edition

Option Processing

TestBean 클래스의 자동 빈등록 이유

Resolved

Written on

·

691

8

public class AutowiredTest {

@Test
public void autowiredOption() {
ApplicationContext ac = new AnnotationConfigApplicationContext(TestBean.class);
}

위의 예제를 보면 TestBean이 자동으로 컨테이너에 빈으로 등록된다고 하셨는데
@Autowired가 있기 때문에 그런 것 같은데 맞나요?
springoop

Quiz

66% of people got it wrong. Give it a try!

What are the main reasons why Field Injection is generally not recommended?

Because it is difficult to guarantee immutability

Because changing dependencies is easy

Because it's difficult to test with pure Java code

Because writing configuration code is complex

Answer 11

2

yh님의 프로필 이미지
yh
Instructor

안녕하세요. lbd4946님^^

추가 질문을 듣고 어떤 것을 물어보신지 이해가 되었습니다. 제가 조금 더 풀어서 설명을 해드릴께요.

1. 먼저 new AnnotationConfigApplicationContext(TestBean.class); 라고 하면 TestBean이 스프링 빈으로 등록됩니다. 이때 TestBean 자체는 아무 애노테이션이 없어도 등록이 됩니다^^! 처음에는 설정 정보가 필요하니, 보통 TestBean 같은 설정 정보를 등록하는 용도로 많이 사용합니다.

2. @Bean은 TestBean 같은 곳에 아마도 추가되어 있을거에요. 이렇게 TestBean 같은 스프링 빈에 @Bean이 붙어있으면 이 메서드들을 호출해서 스프링 빈으로 등록합니다.

3. @Configuration, @Component는 @ComponentScan이라는 자동 등록 기능에 의해서 스프링 빈에 등록될 수 있습니다. TestBean에도 아마 @Configuration이 붙어있을 건데, 이때는 new AnnotationConfigApplicationContext(TestBean.class)라고 이미 적어주었기 때문에 자동 등록 기능에 의해서 스프링빈에 등록된 것은 아니고, 스프링 컨테이너 생성 시점에 바로 스프링 빈으로 등록됩니다. 물론 @Configuration 자동 등록 기능에 의해서도 스프링 빈으로 등록될 수 도 있습니다^^

감사합니다.

1

lbd49464369님의 프로필 이미지
lbd49464369
Questioner

이해가 되었습니다!!! 

감사합니다. 혼자 정리 다시 해보면서 확실히 이해하면 될 것 같아요!!

감사합니다!!

1

yh님의 프로필 이미지
yh
Instructor

질문을 자세히 잘 풀어서 남겨주셔서 감사합니다^^

1. TestBean에 @Configuration이 없고, @Bean도 없으면: 스프링 빈으로만 등록됩니다.

2. TestBean에 @Configuration이 달렸고, @Bean도 존재: 스프링 빈으로 등록되고, 추가로 스프링이 @Bean을 보고 설정 정보로 사용합니다. 여기서 @Component는 없어도 됩니다. (@Component는 @ComponentScan의 대상으로만 사용됩니다.)

추가로 @Bean은 아무 스프링 빈에 등록되어 있어도 스프링이 인지해서 스프링 컨테이너에 해당 빈을 등록합니다. 예를 들어서 다음과 같은 MemberService가 스프링 빈으로 등록되어 있다고 할 때, 여기에 @Bean이 있어도 됩니다. 스프링이 MemberService를 스프링 빈으로 등록하기만 하면, 그 안에 @Bean 이라고 붙은 정보를 다 찾아서 스프링 컨테이너에 등록해줍니다^^!

class MemberService{ 

    @Bean

    public Hello() {

      return new Hello();

    }

}

도움이 되셨길 바래요^^ 혹시 의문이 해결되지 않았으면 추가로 질문남겨주세요 :)

1

yh님의 프로필 이미지
yh
Instructor

안녕하세요. TestBean님^^

@Autowired때문은 아니구요.

new AnnotationConfigApplicationContext(xxx)에 인자로 넘어온 클래스는 자동으로 스프링 빈으로 등록됩니다.

즐거운 추석 되세요^^!

0

감사합니다

0

yh님의 프로필 이미지
yh
Instructor

ㅎㅎ 괜찮아요^^! lbd4946님 스프링 핵심 원리 강의이니 확실하게 이해하는게 중요합니다!

앞에서 이야기하신 부분들을 잘 이해하셨습니다.

그런데 추가로 설명하신 부분은 좀 모호한 부분이 있어서 혹시나 해서 제가 추가 설명을 드릴께요. 다음 부분이요.

------------

추가로 ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
ac.getBean(...); 을 하는 행위를 해주는 것이 @Autowired 입니다.

------------

이 코드 자체는 @Autowired와는 관계가 없습니다.

ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);

코드를 풀어서 말씀드리면

1. new AnnotationConfigApplicationContext(AutoAppConfig.class);를 실행하면 스프링 컨테이너가 생성되고, 스프링 빈들도 모두 생성이 되고, 초기화 작업까지 끝이 납니다.

2. 이 과정에서 스프링 빈에 @Autowired라는 애노테이션이 있으면 의존관계 자동 주입이 일어납니다.

(@Autowired라고 하면 결국 스프링 빈 내부에서는 ac.getBean(...)이 일어난다고 생각하시면 됩니다.(디테일한 차이는 있습니다.))

3. ApplicationContext ac = 이렇게 생성이 끝난 스프링 컨테이너의 참조값을 ac에 넣어둡니다.

감사합니다. 혹시라도 잘 해결되지 않은 부분이 있으면 언제든지 편하게 질문주세요^^!

0

lbd49464369님의 프로필 이미지
lbd49464369
Questioner

답변 감사합니당

자꾸 도돌이표 질문을 드리는 것 같아 죄송합니다 ㅜ.ㅜ

이해한게 맞는지 확인 부탁드립니다!!!

AnnotationConfigApplicationContext빈의 용도는 이름 그대로 어노테이션으로 설정된 클래스를 읽어 컨테이너를 생성하고

컨테이너에 빈으로 등록하는 역할을 하는 것이고, TestBean에 @Configuration이 달려있지 않아도 동일하게 빈으로 등록을 해줍니다.

다만 @Bean이 클래스 내에 정의 되어 있다면 같이 빈으로 등록을 해주는 것이구요.

결국 생명주기?? 라고 해야할지 모르겠지만, 생명주기락고 한다면 크게 3가지로 **컨테이너 생성** -> **빈등록** -> **의존관계주입**

으로 생각합니다. 

AnnotationConfigApplicationContext는 BeanFactory의 하위 레벨이기 때문에 결국 컨테이너이고, 

그렇기 때문에 new AnnotationConfigApplicationContext(TestBean.class)를 했을 때 TestBean에 @Configuration이 없지만, 

컨테이너를 먼저 생성 후 TestBean을 등록을 할 수 있습니다.

@Component는 3가지 생명 주기를 손쉽게 할 수 있게 해주는 것이구요. 

다만, @Configuration이 없을 때의 단점은, 싱글톤이 보장되지 않는다는 것 이구요. 자바 왜냐하면, 결국 자바코드이기 때문에

아래와 같을 때 memberService()에 있는 return new MemberMemoryRepository(); 1번, 

memberRepository()에 있는 return new MemberMemoryRepository(); 1번 
총 2번이 생성 되기 때문에 memberService()의 값과, memberRopository()의 값은 싱글톤이 아니게 된니다.

public class AppConfig {

    @Bean
    public MemberService memberService() {
        System.out.println("AppConfig.memberService");
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        System.out.println("AppConfig.memberRepository");
     }
}

추가로 ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
ac.getBean(...); 을 하는 행위를 해주는 것이 @Autowired 입니다.

감사합니다!!!  친철한 답변 감사합니다!!

0

yh님의 프로필 이미지
yh
Instructor

답변을 조금 더 보충드릴께요.

new AnnotationConfigApplicationContext(TestBean.class); 가 있을 때

1. TestBean에 @Configuration이 없고, @Bean도 없으면: TestBean만 스프링 빈으로만 등록됩니다.

2. TestBean에 @Configuration이 달렸고, @Bean도 존재: TestBean이 스프링 빈으로 등록되고, 추가로 스프링이 @Bean을 보고 설정 정보로도 사용합니다.

사실 스프링 컨테이너는 스프링 빈 중에서 @Bean이 등록된 메서드가 있으면 모두 스프링 빈으로 등록합니다^^!

그렇게 하려면 스프링 빈이 최소 하나는 등록이 되어 있어야 하는데,

그게 바로 new AnnotationConfigApplicationContext(TestBean.class); 라고 이해하시면 됩니다.

혹시 의문이 해결되지 않으면 편하게 답변 남겨주세요^^

안녕하세요. 답글 달아주시는것을 보고 이해 안되는게 있어 질문드립니다.

-----------------------------

답변

new AnnotationConfigApplicationContext(TestBean.class); 가 있을 때

1. TestBean에 @Configuration이 없고, @Bean도 없으면: TestBean만 스프링 빈으로만 등록됩니다.

2. TestBean에 @Configuration이 달렸고, @Bean도 존재: TestBean이 스프링 빈으로 등록되고, 추가로 스프링이 @Bean을 보고 설정 정보로도 사용합니다.

---------------------------------

2번 답변을 보시면 @Bean을 통해 추가로 스프링이 @Bean을 보고 설정 정보로도 사용합니다 라고 말씀하셨는데 여기서 말씀하신 설정정보가 어떤건지 알수있을까요? 

@Bean 이 없는 1번의 경우에는 TestBean이 스프링빈으로만 등록되고 설정정보로 사용 안된다는건 Test빈이 가지고 있는 정보는 사용하지 않는다는 뜻인가요?

오래전 답변이시지만, 이해가 잘 가지않아 질문드립니다. 감사합니다!

yh님의 프로필 이미지
yh
Instructor

안녕하세요. 심모님 너무 오래된 질문이어서 궁금하신 내용을 코드로 직접 테스트 보시고 정리해서 새로 올려주시면 도움을 드리겠습니다.

감사합니다.

0

lbd49464369님의 프로필 이미지
lbd49464369
Questioner

결국

new AnnotationConfigApplicationContext(TestBean.class);

위의 코드가

**@Configuration**과 **@Bean**으로 등록 되어 있으면 등록된 빈 설정 정보를 가져오게 되는 것 이고,

없다면 위의 코드에서 빈으로 등록하게 되는 것이 맞는 건가요?

0

lbd49464369님의 프로필 이미지
lbd49464369
Questioner

답변 감사합니다!!! 추가 질문이 있습니다.

먼저 예제는 아래와 같은 예제입니다.

1. TestBean에는 @Configuration이 없고, @Bean도 없습니다. 해당 예제는 주입할 스프링 빈이 없을 때 통과 시키기 위한

예제입니다. 하지만 이런 상황에 TestBean을 스프링 빈으로 등록하기 위해 

new AnnotationConfigApplicationContext(TestBean.class);

위의 코드로 빈 등록을 한 것이라고 이해 되었습니다. 즉, TestBean 클래스에서 아무런 정보도 없지만 해당 코드로 인해

해당 클래스를 빈으로 등록할 수 있는 것 같습니다.

2. 만약 TestBean에 @Configuration이 달렸고, @Bean도 존재 하거나 @Component이 달렸을 때는

컨테이너가 생성될 때!!! 빈으로 등록하고,

new AnnotationConfigApplicationContext(TestBean.class);

여기서는 등록된 정보를 가져오는 역할만 하는 것으로  보이는데 맞을까요?

즉, 1번일 때의 역할은 등록도 하고 설정정보를 가져오기도 하며,

2번 일 때는 설정정보만 가져오는 것으로 이해 되었습니다.

앗!! 혹시 오해 하시고, 더욱 자세한 답변을 주실까봐 남겨요

@Bean이 존재하는 클래스에 @Configuration이 있을 때와 없을 때의 차이는

강사님께서 답변 해주셔서 알고 있습니다

없어도 스프링 빈으로 등록은 되지만,

존재할 때는 싱글톤이 보장되지만, 없을 때는 보장되지 않는다!!

public class AutowiredTest {

    @Test
    public void autowiredOption() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(TestBean.class);
        TestBean bean = ac.getBean(TestBean.class);
        System.out.println("bean = " + bean);
    }

    static class TestBean {

        //호출 안됨
        @Autowired(required = false)
        public void setNoBean1(Member member) {
            System.out.println("setNoBean1 = " + member);
        }
        //null 호출
        @Autowired
        public void setNoBean2(@Nullable Member member) {
            System.out.println("setNoBean2 = " + member);
        }
        //Optional.empty 호출
        @Autowired(required = false)
        public void setNoBean3(Optional<Member> member) {
            System.out.println("setNoBean3 = " + member);
        }
    }
}

0

lbd49464369님의 프로필 이미지
lbd49464369
Questioner

제가 이해를 잘못하고 있었나 봐요

AnnotationConfigApplicationContext(xxx.class)
의 기능은 이미 @Bean, @Comfiguration, @Component에 의해 등록된 bean을 가져오는 것으로 이해 했는데 아닌가요?
lbd49464369's profile image
lbd49464369

asked

Ask a question