Spring Bean이란?
Spring Bean은 스프링 컨테이너가 생성 및 관리하는 자바 객체를 의미한다.
즉, 객체의 생성, 초기화, 소멸등의 생명주기를 컨테이너가 담당하여 객체 간 결합도를 낮추고, 재사용성을 높이는 역할을 한다.
✅ 스프링 빈(Bean)의 등록 방법
스프링 빈 등록 방법은 크게 3가지 방법이 존재한다.
- xml에 직접 등록
- @Bean 어노테이션을 이용
- @Component, @Controller, @Service, @Repository 어노테이션을 이용
1. XML 설정을 이용한 방식 (옛날 방식, 잘 안 쓴다.)
`applicationContext.xml` 같은 XML 파일을 사용하여 직접 빈을 등록하는 방법이다.
스프링 3 이전에 많이 사용되었으나, 현재는 어노테이션 기반 설정이 주로 사용된다. 하지만 본인 포함 회사에 부트가 아닌 스프링 프레임워크로 제작된 옛 프로젝트를 유지보수한다면, 마주칠 가능성도 있다.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.example.service.UserService"/>
</beans>
위와 같이 현재 사용하는 방식 어노테이션을 사용하는 게 아닌, XML 파일에 bean을 설정하여 사용하게 된다.
나름 명확한 면은 있지만, XML 파일 특성상 가독성이 떨어져 유지보수가 어려운 문제가 있다.
2. @Bean 어노테이션을 이용한 등록
`@Configuration` 클래스 내부에서 `@Bean` 어노테이션을 사용하여 직접 빈을 등록하는 방법이다.
XML 설정보다 코드 관리가 편리하고, 타입 안정성이 높다.
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
주로 외부 라이브러리의 클래스를 빈으로 등록할 때 유용하다. (`@Component`로 등록할 수 없는 경우)
@Component와 @Bean?
@Component와 @Bean은 모두 스프링에서 빈(Bean)을 등록하는 데 사용할 수 있는 어노테이션입니다.
@Component는 클래스에 적용하며, 개발자가 직접 변경이 가능한 대상에 사용합니다.@Bean은 메서드에 적용하며, 보통 개발자가 직접 변경이 어려운 대상에 사용하는 것이 권장됩니다.
@Component 어노테이션이 적용된 클래스는 @Autowired 어노테이션을 사용하여 다른 빈들을 주입받을 수 있습니다.
3. @Component, @Service, @Repository, @Controller를 이용한 등록 (컴포넌트 스캔)
@Component 계열 어노테이션을 사용하여 스프링이 자동으로 빈을 스캔하도록 하는 방식이다.
가장 많이 사용되는 방법이며, 간단한 설정으로 빈을 등록할 수 있다.
@Component
public class UserService {
}
@Service // 서비스 로직
public class UserService {
}
@Repository // 데이터베이스 관련 로직
public class UserRepository {
}
@Controller // MVC 컨트롤러
public class UserController {
}
간결한 코드 작성이 가능하고, 빈의 역할을 명확히 구분 가능하다. ( @Service, @Repository 등)
✅ 스프링 빈(Bean)의 생명주기 (Lifecycle)
스프링 컨테이너는 객체의 생성부터 소멸까지 자동으로 관리한다고 했다. 그렇다는 건 스프링 빈의 생명주기는 빈이 생성되고 사용되었다가 소멸되는 과정을 의미한다.
스프링 빈의 생명주기 단계
1. 객체 생성 (Initialization)
- 빈의 인스턴스가 생성됨을 의미한다.
- 빈 스코프(Singleton, Prototype 등)에 따라 생성 방식이 다를 수 있다.
- 아까 정의한 스프링 빈 등록방법으로 등록된 객체를 스프링이 관리한다.
2. 의존성 주입 (DI)
- @Autowired 또는 생성자 등을 이용해 의존성이 주입하는 단계를 의미한다.
- 스프링 컨테이너는 작성된 코드를 기반으로 생성된 빈을 주입해 주게 된다. (필요한 의존 관계가 설정된다.)
3. 초기화 (Initialization) 콜백
- 스프링 빈은 객체가 컨테이너의 생성되고 의존관계가 주입되면 사용할 준비가 끝났다고 볼 수 있다.
- 개발자 입장에선 준비가 끝났다는 것을 알 수가 없으니, 의존관계 주입이 완료되는 시점을 알기 위해 스프링에서 콜백 메서드를 통해 초기화 시점을 알려주는 기능을 제공한다.
- 즉, 빈이 생성되고 빈의 의존관계 주입이 완료된 후 호출하는 시점을 의미한다.
- `@PostConstruct`, `InitializingBean` 등이 있다.
4. 사용 (Ready to Use)
- 빈이 준비되었으니, 애플리케이션 내에서 활용되는 시점이다.
5. 소멸 (Destruction) 콜백
- 초기화 콜백과 마찬가지로, 애플리케이션 종료와 같은 컨네이터에서 Bean을 제거할 때 실행된다.
- 즉, 빈이 소멸되기 직전에 호출되며, 이 과정이 끝나면 빈이 메모리에서 제거된다.
- `@PreDestroy`, `DisposableBean`, `destroy-method` 등을 활용 가능하다.
이렇듯 스프링에선 컨테이너를 활용해 빈의 생명주기 관리 및 생명주기 콜백을 지원한다. 이후 포스팅에선 스프링의 빈 생명주기 콜백에 대표적인 어노테이션인 `@PostConstruct`와 `@PreDestroy`에 더 자세히 알아보도록 하자.
✅ 스프링 빈(Bean)의 사용 이유?
스프링 빈에 사용 방법과 생명주기를 알아봤고, 마지막으로 사용 이유를 알아보자.
토비의 스프링 1권 1장을 "오브젝트와 의존관계"를 보면, 객체 지향 설계 원칙을 적용한 스프링의 핵심 개념이 등장한다.
특히, 스프링이 객체(오브젝트)를 어떻게 관리하고, 왜 스프링 빈을 활용해야 하는지 강조하는 데 그 내용이 스프링 빈을 사용하는 이유에 기반이 된다.
1. 객체 생성과 관계 설정의 분리 (관심사의 분리)
만약 아래 예제 코드와 같이 `new`를 사용한다면 객체 간에 결합도가 높아져 변경이 어려워진다.
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao() {
this.connectionMaker = new DConnectionMaker(); // 직접 객체 생성
}
}
이 방식에 문제점은 `DConnectionMaker`를 변경하면 `UserDao`도 수정해야 한다. 이러한 과정을 일어나는 것을 결합도가 높다고 표현한다.
객체 생성과 관계 설정이 한 클래스에서 처리됨에 따라 관심사가 분리가 안된다. 이러한 코드는 `Mock` 객체를 주입하기 어렵기 때문에 테스트하기 어려운 코드가 작성되게 된다.
2. 객체 생성과 관계 설정을 외부에서 담당하도록 변경
UserDao는 직접 ConnectionMaker를 생성하지 않고, 외부에서 주입받도록 변경한다.
이 과정에서 스프링 빈이 등장하게 된다.
public class UserDao {
private ConnectionMaker connectionMaker;
// 외부에서 주입받음 (DI)
public UserDao(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
}
- UserDao는 더 이상 DConnectionMaker에 의존하지 않아 결합도가 낮아진다.
- ConnectionMaker를 원하는 다른 구현체로 쉽게 변경 가능함으로 코드 유연성도 증가하게 된다.
- 또한, 테스트 시 Mock 객체를 쉽게 주입할 수 있으므로 단위 테스트가 쉬워지게 된다.
3. 객체의 생명주기를 스프링 컨테이너가 관리
위에서 언급했듯이 객체의 생명주기를 스프링 컨테이너가 관리한다. 이는 즉, 객체를 언제, 어떻게 생성하고, 관리할지를 개발자가 직접 결정하는 것이 아니라, 스프링 컨테이너가 담당함에 따라 개발자가 객체 생성 및 관계 설정을 직접 신경 쓰지 않아도 된다.
4. 싱글톤 패턴 적용 (객체 공유)
스프링 컨테이너는 기본적으로 빈을 싱글톤(하나만 생성)으로 관리한다. 같은 UserDao 빈을 여러 번 요청해도, 같은 인스턴스를 반환한다는 말과 같다.
UserDao dao1 = context.getBean("userDao", UserDao.class);
UserDao dao2 = context.getBean("userDao", UserDao.class);
System.out.println(dao1 == dao2); // true (같은 객체)
이를 통해 불필요한 객체 생성을 방지하여 메모리 절약 및 동일한 인스턴스 공유를 통한 일관성 유지가 가능하다.
5. 환경 설명 및 유연한 설정 관리
마찬가지로 위에 빈 등록 방법을 설명할 때 한 이야기로, @ComponentScan, @Configuration, @Bean 등을 활용하여 유연하게 객체를 주입할 수 있다.
또한, 프로파일(Profile) 설정을 활용해 개발/운영 환경을 다르게 구성도 가능하다.
결론 및 1분 답변
스프링 빈은 객체의 생명주기를 스프링 컨테이너가 자동으로 관리하여 개발자가 비즈니스 로직에 집중할 수 있도록 도와줍니다.
의존성 주입(DI)을 통해 객체 간 결합도를 낮추고, 유지보수성을 높이며, 테스트도 용이해집니다. 또한, 싱글톤 패턴을 적용하여 불필요한 객체 생성을 방지하고 성능을 최적화합니다.
AOP를 활용하면 트랜잭션 관리, 로깅, 보안 같은 공통 기능을 전역적으로 적용할 수 있어 중복 코드가 줄어듭니다.
마지막으로, @ComponentScan, @Configuration, @Bean 등의 설정을 활용해 유연한 환경 구성이 가능하며, 프로파일을 통해 개발/운영 환경을 분리할 수 있습니다.
참조
스프링 핵심 원리 - 기본편 강의 | 김영한 - 인프런
김영한 | , 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보세요! 📢 수강 전 확인해주세요! 본 강의는 자바 스프링 완전 정복 시리즈의 두 번째 강의입니다. 우아한형제들 최연
www.inflearn.com
토비의 스프링 6 - 이해와 원리 강의 | 토비 - 인프런
토비 | , 스프링 구루(Guru)의 귀환!14년만에 돌아온 토비의 스프링6오래 전 출간되어 많은 개발자들에게 사랑을 받았던 <토비의 스프링 3>이 14년 만에 돌아왔습니다!<토비의 스프링 3.1> 책에서 다
www.inflearn.com
'Framework > Spring' 카테고리의 다른 글
[스진초5기/Spring] DTO, Entity 변환은 어느 계층에서 일어나야할까? (0) | 2023.11.16 |
---|---|
[스진초5기/Spring] DTO, VO, Entity (0) | 2023.11.08 |
[스진초5기/Spring] 스프링 3계층과 DI의 관계 (0) | 2023.11.05 |
[스진초5기/Spring] 그래서 Controller가 뭐야? (1) | 2023.11.03 |
[스진초5기/Spring] Controller, Service, Repository (3계층) (0) | 2023.10.31 |