스프링 컨테이너 : 객체의 생명 주기를 관리하며, 생성된 자바 객체
즉 스프링에서 자바 객체들을 관리하는 공간
자바 객체를 스프링에선 빈(Bean)이라고 한다.
ApplicationContext 이 스프링 컨테이너.
ApplicationContext 는 인터페이스로, 구현체로 AnnotationConfigApplicationContext() 가 있다.
파라미터로 구성 정보가 저장되어있는 클래스를 넣어주어야 한다.
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
간단한 예시를 하나 만들어보겠다.
홈페이지에서 회원을 관리하기 위해, 회원 정보를 저장하는 MemberRepository,
저장된 회원 정보를 통해 특정 로직 (가입, 조회 등) 을 수행하는 MemberService 가 있다고 하자.
MemberService 는 MemberRepository 에 의존성을 가지고 있다.

이를 구성하는 AppConfig 코드는 아래와 같다.
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
@Bean 은 아래 객체를 Bean 으로 만들 수 있도록 해준다.
이때 Bean 의 이름을 따로 설정하지 않으면 클래스의 이름에서 맨 앞자를 소문자로 바꾼 것을 사용한다.
여기에선 memberService, memberRepository 를 이름으로 사용할 것이다.
확인을 한번 해보면
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean(MemberService.class);
MemberRepository memberRepository = applicationContext.getBean(MemberRepository.class);
System.out.println(memberService.getMemberRepository());
System.out.println(memberRepository);
각 객체가 잘 만들어졌고, 의존관계도 잘 주입이 되었다.
그런데 한 가지 문제점은, 레파지토리 출력 결과 두 레파지토리의 주소가 다르다는 것이다.
이를 해결하기 위해 레파지토리에 싱글톤 패턴을 적용하고, 의존성 주입 시 이미 생성된 객체만 꺼내가도록 설정해야 한다.
그러나 이 방법은 여러 문제점이 있어서 (코드가 늘어남, 테스트하기 어려움, private 생성자로 자식 클래스 만들기 어려움)
Spring 에선 싱글톤 컨테이너를 제공한다
스프링 컨테이너는 싱글턴 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다!
대신, 싱글턴의 특성상 하나의 같은 객체 인스턴스를 여러 클라이언트가 공유하기 때문에
무상태(stateless)로 설계해야 한다.
즉 객체 내부의 값을 변경하지 않도록 해야 한다.
이를 위해 가급적 읽기만 가능해야 하며, 그 값을 직접 return 해 요청한 클라이언트가 직접 사용하도록 하자
그럼 마지막으로 싱글턴 컨테이너를 적용하기 위해선 AppConfig에 @Configuration을 추가하면 된다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
이후 동일한 테스트를 하면 memberService의 리파지토리와 직접 불러온 memberRepository가 동일한 주소임을 확인할 수 있다.
이게 가능한 이유는,
CGLIB라는 바이트코드 조작 라이브러리를 사용해 Bean으로 등록하는 클래스를 상속받는 임의의 다른 클래스를 만들고, 이걸 스프링 빈으로 등록하기 때문이다!
'코딩 > JAVA 공부' 카테고리의 다른 글
| [Spring] 의존성 관계 자동 주입 (1) | 2023.05.14 |
|---|---|
| [Spring] 컴포넌트 스캔 (0) | 2023.05.13 |
| [JAVA] 가변 리스트, 불변 리스트 / 리스트에서 반복문 사용하기 (0) | 2023.04.12 |
| [JAVA} 가변인수, Wrapper Class (0) | 2023.04.09 |
| 논리 연산자 &, |와 &&, ||의 차이 (0) | 2023.04.07 |