기본 개념
- 빈 (Bean): 스프링이 관리하는 객체
- 스프링 IoC 컨테이너: Bean(객체)을 모아둔 저장소이자 빈 관리 -> 객체의 생명주기(Life Cycle)인 생성과 소멸 관리, 객체 간 의존성 주입 등
@Bean 어노테이션의 주요 내용
- @Configuration 설정된 클래스의 메소드에서 사용가능
- 메소드의 리턴 객체가 스프링 빈 객체임을 선언함
- 빈의 이름은 기본적으로 메소드의 이름
- @Bean(name="name")으로 이름 변경 가능
- @Scope를 통해 객체 생성을 조정할 수 있음
- @Component 어노테이션을 통해 @Configuration 없이도 빈 객체를 생성할 수도 있음
- 빈 객체에 init(), destroy() 등 라이프사이클 메소드를 추가한 다음 @Bean에서 지정할 수 있음
// 빈 이름 규칙: 클래스의 앞글자만 소문자로 변경
스프링 빈 생명 주기
1. 스프링 IoC 컨테이너 생성
2. 빈 등록
방법 1) 컴포넌트 스캔과 자동 의존관계 설정: @Component 어노테이션 사용
@Controller, @Service, @Repository는 @Component를 포함하고 있음
@Component
public class ProductService { ... }
스프링 서버가 시작될 때 스프링 IoC 에 '빈' 저장
@Component 클래스에 대해서 스프링이 해 주는 일
// 1. ProductService 객체 생성
ProductService productService = new ProductService();
// 2. 스프링 IoC 컨테이너에 빈 (productService) 저장
// productService -> 스프링 IoC 컨테이너
@Component 적용 조건: @ComponentScan 에 설정해 준 packages 위치와 하위 packages 들
@SpringBootApplication 에 의해 default 설정이 되어 있음
@Configuration
@ComponentScan(basePackages = "com.sparta.springcore")
class BeanConfig { ... }
방법 2) 객체를 직접 생성하여 빈으로 등록
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // 설정 클래스에 @Configuration 어노테이션 추가
public class BeanConfiguration { // 설정 클래스 생성
@Bean
public ProductRepository productRepository() {
String dbUrl = "jdbc:h2:mem:springcoredb";
String dbId = "sa";
String dbPassword = "";
return new ProductRepository(dbUrl, dbId, dbPassword);
}
}
스프링 서버가 시작될 때 스프링 IoC 에 '빈' 저장
// 1. @Bean 설정된 함수 호출
ProductRepository productRepository = beanConfiguration.productRepository();
// 2. 스프링 IoC 컨테이너에 빈 (productRepository) 저장
// productRepository -> 스프링 IoC 컨테이너
3. 객체 생성
4. 의존관계 주입
- 생성자 주입 : 객체의 생성과 의존관계 주입이 동시에 일어남
- Setter, Field 주입 : 객체의 생성 -> 의존관계 주입으로 라이프 사이클이 나누어져 있음
5. 초기화 콜백 메소드 호출
빈이 생성되고 빈의 의존관계 주입이 완료된 후 호출 되는 것
6. 사용
방법 1) 필요한 곳에서 @Autowired를 통해 의존성 주입을 받아 사용
- 멤버변수 선언 위에 @Autowired → 스프링에 의해 DI (의존성 주입) 됨
@Component
public class ProductService {
@Autowired
private ProductRepository productRepository;
// ...
}
- '빈' 을 사용할 함수 위에 @Autowired → 스프링에 의해 DI (의존성 주입) 됨
@Component
public class ProductService {
private final ProductRepository productRepository;
@Autowired
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
// ...
}
방법 2) ApplicationContext: 스프링 IoC 컨테이너에서 빈을 수동으로 가져오는 방법
@Component
public class ProductService {
private final ProductRepository productRepository;
@Autowired
public ProductService(ApplicationContext context) { // ApplicationContext: 스프링 IoC컨테이너를 다루기 위한 클래스
// 1.'빈' 이름으로 가져오기
ProductRepository productRepository = (ProductRepository) context.getBean("productRepository");
// 2.'빈' 클래스 형식으로 가져오기
// ProductRepository productRepository = context.getBean(ProductRepository.class);
this.productRepository = productRepository;
}
// ...
}
cf) @Autowired 조건
- @Autowired 적용 조건: 스프링 IoC 컨테이너에 의해 관리되는 클래스에서만 가능
- @Autowired 생략 조건
- Spring 4.3 버전 부터 @Autowired 생략가능
- 생성자 선언이 1개 일 때만 생략 가능
7. 소멸 전 콜백 메소드 호출
빈이 소멸되기 직전에 호출
8. 종료
스프링에서는 지원하는 빈 생명 주기 콜백
1. 인터페이스(InitializingBean, DisposableBean) 상속받아 메소드를 오버라이드하여 초기화 콜백 함수 구현
public class ExampleBean implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception { // InitializingBean의 afterPropertiesSet()
// 초기화 콜백 (의존관계 주입이 끝나면 호출)
}
@Override
public void destroy() throws Exception { //DisposableBean의 destroy()
// 소멸 전 콜백 (메모리 반납, 연결 종료와 같은 과정)
}
}
단점
- 스프링 전용 인터페이스인 InitializingBean 인터페이스, DisposableBean 인터페이스를 상속하므로, 스프링 인터페이스에 의존적
- 메소드를 오버라이드 하기 때문에 이름 변경 불가
- 코드가 커스터마이징 할 수 없는 외부 라이브러리에 적용 불가
2. 설정 정보(Configuration)에 초기화 메서드, 종료 메서드 지정
class ExampleBean {
public void init() throws Exception {
// 초기화 콜백 (의존관계 주입이 끝나면 호출)
}
public void close() throws Exception {
// 소멸 전 콜백 (메모리 반납, 연결 종료와 같은 과정)
}
}
@Configuration
class LifeCycleConfig { // 클래스 내부에 초기화/종료 메소드를 구현
@Bean(initMethod = "init", destroyMethod = "close") // 호출될 메소드 이름 작성
public ExampleBean exampleBean() {
ExampleBean exampleBean = new ExampleBean();
return exampleBean;
}
}
장점
- 메소드 이름 지정 가능
- 스프링 빈이 스프링 코드에 의존하지 않음
- 코드를 고칠 수 없는 외부 라이브러리에 초기화, 종료 메소드를 적용 가능
단점
- Bean 지정시 initMethod와 destoryMethod를 직접 지정해야하는 번거로움
@Bean의 destoryMethod 속성 특징
라이브러리는 대부분 종료 메소드명이 close 혹은 shutdown
@Bean의 destoryMethod는 기본값이 inferred(추론)으로 등록 즉, close, shutdown이라는 이름의 메소드가 종료 메소드라고 추론하고 자동으로 호출해줌 -> 종료 메소드를 따로 부여하지 않아도 됨
추론 기능을 원하지 않는다면 명시적으로 destroyMethod="" 지정 필요
3. @PostConstruct, @PreDestroy 어노테이션으로 콜백 함수 커스터마이징
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class ExampleBean {
@PostConstruct
public void initialize() throws Exception {
// 초기화 콜백 (의존관계 주입이 끝나면 호출)
}
@PreDestroy
public void close() throws Exception {
// 소멸 전 콜백 (메모리 반납, 연결 종료와 같은 과정)
}
}
장점
- 최신 스프링에서 권장하는 방식
- 컴포넌트 스캔과 활용도가 높음
- 스프링 인터페이스에 의존적이지 않음: import문에 패키지가 javax.annotation.xxx 로 스프링에 종속적인 기술이 아닌 JSR-250이라는 자바 표준으로 스프링이 아닌 다른 컨테이너에서도 동작
단점
- 코드 수정이 불가능한 외부 라이브러리에는 적용할 수 없음
'Spring > Springboot' 카테고리의 다른 글
📝 Controller, Service, Repository 가 무엇인가요? (0) | 2022.11.16 |
---|---|
스프링 빈 생명 주기(Spring Bean Life Cycle) (0) | 2022.11.09 |
Controller, Service, Repository의 역할 (0) | 2022.11.08 |
Controller와 HTTP Request 메시지 (0) | 2022.11.08 |
빌드 관리 도구 Maven과 Gradle 비교 (0) | 2022.11.08 |