🚩목차
스프링 컨테이너와 스프링 빈
스프링 컨테이너란
스프링 컨테이너란 스프링 빈(객체)을 싱글톤 패턴으로 생성하고 관리하는 저장 공간입니다. 객체를 싱글톤 패턴으로 관리한다는 말은 스프링 애플리케이션 내에서 해당 클래스 인스턴스를 단 하나만 생성해서 여러 컴포넌트에서 재활용 한다는 의미입니다.
스프링 컨테이너는 BeanFactory 인터페이스를 의미합니다. getBean()으로 저장소에 등록된 빈을 가져오거나, getType()으로 빈 타입을 확인하는 등 다양한 메소드를 제공합니다. 현대에는 BeanFactory를 구현해 다양한 기능을 추가 탑재한 ApplicationContext 인터페이스를 스프링 컨테이너로 주로 사용합니다.
빈 수동 등록
ApplicationContext는 저장소에 등록할 스프링 빈의 정보를 어디서 가져올까요? 바로 개발자가 전달한 빈(객체) 설정 정보입니다. 마치 레고의 설계도 처럼 개발자가 빈 설정 정보를 전달하면, 스프링 컨테이너는 해당 설정 정보를 토대로 객체를 싱글톤 패턴으로 단 하나만 생성해 보관합니다.
그럼 개발자는 어떻게 설정 정보를 넘길 수 있을까요? 바로 생성자 매개변수로 전달하면 됩니다. ApplicationContext는 빈 설정 정보가 어떤 형식으로 작성되었느냐에 따라 그 구현체가 달라지는데요, 자바 클래스로 작성하면 AnnotationConfigApplicationContext 으로, XML 형식으로 작성하면 XmlApplicationContext 으로 구현체를 선택하면 됩니다.
스프링 컨테이너가 다양한 설정 정보를 토대로 빈을 생성할 수 있는 이유는 바로 BeanDefinition 추상화에 의존하기 때문입니다. 다음은 스프링 공식 문서에 작성된 Bean Definition에 관한 설명입니다.
A bean definition is essentially a recipe for creating one or more objects. The container looks at the recipe for a named bean when asked and uses the configuration metadata encapsulated by that bean definition to create (or acquire) an actual object.
Bean Definition은 객체를 생성할 때 참고하는 레시피라고 합니다. 그리고 빈 데피니션 안에 담긴 설정 메타데이터를 실제 객체를 만들어낼 때 활용한다고 작성되어 있습니다.
빈 자동 등록
위처럼 스프링 빈은 개발자가 작성한 설정정보를 바탕으로 생성될 수도 있지만, 모든 객체에 대한 레시피를 일일이 작성한다면 매우 번거로워질 것입니다. 따라서 스프링은 프로젝트에서 객체를 자동으로 스캔하고 컨테이너에 등록할 수 있도록 컴포넌트 스캔을 제공합니다.
방법은 매우 간단합니다. 스프링 빈으로 등록할 클래스에 클래스 수준 애너테이션 @Component를 붙여주기만 하면 됩니다. 스프링은 애플리케이션 시작 시점에 자동으로 @Component가 붙은 클래스를 스캔해 싱글톤 빈으로 등록합니다.
자동 스캔 대상이 되는 패키지 범위는 기본적으로 @ComponentScan 애너테이션이 붙은 설정 클래스의 패키지 위치부터 입니다. 스캔 범위를 바꾸려면 @ComponentScan 애너테이션의 옵션인 basePackage로 변경하면 됩니다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
Springboot의 경우 @SpringBootApplication 애너테이션이 @ComponentScan을 포함하고 있어 프로젝트 최상단 패키지 부터 컴포넌트 스캔을 수행합니다. 또한 @Component 외에도 @Controller, @Service, @Repository, @Configuration이 붙은 클래스는 스캔 대상이 됩니다.
의존관계 주입
4가지 방법
스프링 컨테이너는 특정 객체가 의존하고 있는 객체에 @Autowired 애너테이션을 붙이면, 컨테이너에서 해당 빈을 조회해 주입합니다. 객체에 의존 관계를 자동으로 주입하는 방법은 4가지입니다. Spring은 공식적으로 4가지 방법 중 생성자 주입을 권장하고 있습니다.
- 생성자 주입
- 생성자 레벨에 @Autowired 애너테이션을 붙이고 매개변수에 의존할 객체를 명시합니다.
- 만약 해당 클래스에 생성자가 단 하나만 존재한다면 @Autowired 애너테이션을 생략해도 동일하게 동작합니다.
- 필드 주입
- 의존할 객체 필드에 @Autowired 애너테이션을 붙입니다.
- 수정자 주입
- 의존할 객체 필드를 수정하는 수정자(Setter)에 @Autowired 애너테이션을 붙입니다.
- 일반 메서드 주입
의존관계 자동 주입 시 발생 가능한 문제와 해결책
- 주입할 빈이 스프링 컨테이너에 존재하지 않는 경우
- @Autowired(requried=false) required 옵션에 false 값을 작성합니다. 컨테이너에 주입할 빈이 존재하지 않는 경우 , 수정자 메서드 자체가 호출되지 않습니다.
- 주입될 객체에 @Nullable 애너테이션을 작성합니다. 컨테이너에 주입할 빈이 존재하지 않는 경우, null이 입력됩니다.
- 주입될 객체에 Optional로 감쌉니다. 컨테이너에 주입 대상이 존재하지 않는 경우, Optional.empty가 입력됩니다.
- 주입할 빈이 스프링 컨테이너에 여러개 존재하는 경우
- @Autowired 가 붙은 필드의 이름을 빈 이름과 동일하게 매칭시킵니다.
- @Qualifier 애너테이션을 붙여 식별자를 추가합니다.
- @Primary를 클래스 레벨에 붙여 해당 빈에 다른 빈들 보다 주입 우선권을 줍니다.
- 만약 동일 타입으로 조회한 빈이 모두 필요할 경우, Map 또는 List로 받아 사용합니다.
빈 생명주기와 빈 스코프
스프링 빈 생명주기
생명주기란 객체의 생성부터 소멸까지의 과정을 표현한 것입니다. 스프링 빈은 애플리케이션 실행 도중 다음의 생명주기를 갖습니다.
스프링 컨테이너 생성 > 스프링 빈 생성 > 의존관계 주입 > 객체 초기화 콜백 메서드 호출 > 사용됨 > 종료 콜백 메서드 호출 > 소멸
빈 스코프
빈 스코프란 스프링 컨테이너가 특정 객체의 생명주기 중 어느 범위까지 관여하는지를 표현한 것입니다.
- 싱글톤: 스프링 컨테이너는 싱글톤 스코프 객체의 생성부터 소멸까지 전 범위를 관여합니다.
- 프로토타입: 스프링 컨테이너는 프로토타입 스코프 객체의 생성부터 초기화 콜백까지 범위를 관여합니다.
정리
- 스프링 컨테이너는 다양한 설정 정보를 토대로 객체를 생성해 싱글톤으로 관리한다. 컴포넌트 스캔으로 빈을 자동 등록 할 수도 있다.
- 의존관계 자동 주입은 기본적으로 생성자를 사용하되, 변경 가능성이 있는 의존관계에는 수정자를 사용한다.
- 스프링 빈은 생명주기를 가지며, 빈 스코프는 스프링 컨테이너가 빈 생명주기의 어느 범위까지 관여하느냐를 나타낸 것이다.
Reference
'개발 > Spring' 카테고리의 다른 글
[Spring] Spring Data JPA OSIV와 지연 로딩 (3) | 2024.06.11 |
---|---|
Springboot 프로젝트에서 Jasypt 암호화로 yml 설정 파일 프로퍼티 관리하기 (0) | 2024.05.07 |
서블릿과 서블릿 컨테이너란 무엇이고 어떻게 동작할까? - 전통적인 웹 앱 부터 Spring MVC까지 (1) (1) | 2024.04.16 |
Spring Security 인터페이스를 활용한 Rest API 로그인 인증 구현 (1) | 2024.03.31 |
Spring Security 인증 절차 & 핵심 인터페이스 (1) | 2024.03.23 |