Spring을 공부할 때, Spring은 객체를 Bean으로 등록해서 이를 사용함을 알 수 있는데, 여기서 @Configuration 정보가 나오게 된다. Spring의 흐름을 제대로 파악하고자 이번엔 @Configuration을 포스팅한다. 🌱
@Configuration이란?
Spring에서는 Bean을 수동으로 등록할 때, 설정 class 위에 @Configuration을 추가하고, @Bean을 사용해서 수동으로 Bean을 등록할 수 있다.
@Configuration
public class PasswordEncoderConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
//이제 passwordEncoder를 사용하기 위해서는 @Autowired를 작성해줘야한다.(DI)
}
객체 생성 방법들
예를 들어, MemberService란 객체를 사용해야한다고 가정하자. 객체를 사용한다는 의미는 객체의 메소드와 필드를 사용한다는 뜻이고, 이를 위해선 객체를 “생성”부터 해야한다.
이때, “의존한다” = “사용한다”
- 객체 생성을 MemberService 그 자체에서 할 경우
MemberService memberService = new MemberService();
- 객체 생성을 AppConfig에 위임했을 경우
AppConfig appConfig = new AppConfig(); MemberService memberService = appConfig.memberService();
- Spring Container을 사용해서 위임했을 경우
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class) //└ Annotation으로 만든 AppConfig 파일로 ApplicationContext를 만들겠다. MemberService memberService = //applicationContext.getBean("빈 이름", 빈 형태) applicationContext.getBean("memberService", MemberService.class); //아직까지도 Spring 컨테이너에 맡기기만 했지, 제어권 100%를 준 느낌은 x
new AnnotationConfigApplicationContext(AppConfig.class)
: @Configuration이 붙은 AppConfig 파일로 ApplicationContext를 만들겠다.
applicationContext.getBean("memberService", MemberService.class)
: applicationContext.getBean("빈 이름", 빈 형태)
- 3번 방법은 Spring Container에 Bean을 등록하긴 했으나, 제어권을 확실히 줬다고 말할 수 없다.
@Configuration public class AppConfig { @Bean //스프링 빈 등록하기 public MemberService memberService(){ return new MemeberService(); } @Bean pulbic Test test(){ return new Test(memberService()); // 싱글톤 패턴에 의해 2개 생성이 아닌 1개만 생성된다. } }
- DI의 등장 ⇒ Spring에게 제어권을 완전히 넘겨준 case
@Autowired MemberService memberService;
@Autowired
: Spring Container에 등록한 Bean에게 의존관계의 주입이 필요할 때 작성하는 Annotation
AppConfig.java @Configuration public class AppConfig { @Bean //스프링 빈 등록하기 set public MemberService memberService(){ return new MemeberService(); } @Bean pulbic Test test(){ return new Test(memberService()); // 싱글톤 패턴에 의해 2개 생성이 아닌 1개만 생성된다. }
@Configuration의 역할
- Bean을 등록할 때 Singleton이 되도록 보장해준다.
- Spring Container가 Bean을 관리할 수 있도록 한다.
example )
public class MyBean { public MyBean() { System.out.println("MyBean instance created"); } }
public class MyBeanConsumer { public MyBeanConsumer(MyBean myBean) { System.out.println("MyBeanConsumer created"); } }
@Configuration public calss AppConfig { @Bean public MyBean myBean() { return new MyBean(); //호출 1회 } @Bean public MyBeanConsumer myBeanConsumer() { return new MyBeanConsumer(myBean()); //호출 2회 } }
- @Configuration을 작성시,
MyBean instance created MyBeanConsumer created
- @Configuration을 제거시, 호출 2번됨
MyBean instance created MyBean instance created MyBeanConsumer created
∵ @Bean만 사용시 Spring Bean으로 등록은 가능하나, Singleton이 유지되지 않는다.
IoC와 DI (w/ Spring Bean)
“IoC를 구현하기 위해 DI가 필요하다.”
- 자바 빈
: 자바프로그램이 관리하는 객체
- 스프링 빈
: 스프링이 컨테이너에 담아놓고 관리하는 객체
- IoC (제어의 역전)
: 프로그램 흐름의 제어권이 스프링에게 넘어간다.
: 객체의 흐름을 제어하는 주체가 스프링에게 넘어간다.
: 스프링 빈의 흐름을 제어하는 주체가 정반대로 바뀜 (스프링에게 넘어간다.)
- 스프링 컨테이너 (a.k.a IoC, DI, 스프링 컨테이너)
: 스프링 빈을 담아두는 공간
- DI (의존성주입)
: 우리는 의존성을 주입 당하는 역할.(스프링이 해준다)
= 스프링은 의존성을 주입하는 역할
[의존성을 주입해주려면 스프링 빈 (컨테이너 내부에있어야함) 이어야함 !]
: @Configuration + @Bean [DI,IoC 모두의 역할이 될 수 있다 ]
- 스프링아, 나 이거 스프링 빈으로 등록해줘 /ok, 스프링빈으로 생성해서 컨테이너에 등록해줄게
: @Autowired - 스프링아, 여기에 의존성을 주입해줘 / ok, 거기에 주입해줄게 !
IoC와 DI가 장점이다.
기존에는 개발자가 직접 객체의 생성과 소멸을 제어했는데, 스프링은 DI와 IoC로 인해 객체의 생성과 소멸 등 클래스 간의 의존관계를 스프링 컨테이너가 제어한다. 그러므로 클래스들 간의 의존관계가 낮아져서 클래스들의 변경이 자유로워 유지보수가 수월해진다는 장점이 있습니다.
🔗 참고한 URL
https://blogshine.tistory.com/551
Uploaded by N2T