기존에 서블릿을 통해 프론트컨틀로러 핸들러어뎁터 핸들러 맵핑을 구현하고 보드게시판을 만들어 보았다. 하지만 직접 하려니 조금 불안정한부분도 있었고 하여 해당 방식을 미리 만들어놓은 스프링 프레임워크를 공부하여 적용해 보기로 하였다. 우선은 추상적인 개념 보다는 사용방식부터 알아보았다.
mvc 부분은 다음에 보기로 하고 일단은 스프링의 핵심인 컨테이너, 빈부터 고웁해 보기로 하였다.
빈등록은 수동등록과 자동등록으로 나뉜다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl();
}
}
<bean id="..." class="..."/>)@Component
public class MemberServiceImpl implements MemberService {}
@Configuration
@ComponentScan(basePackages = "com.example")
public class AutoAppConfig {}
@ComponentScan 설정 필수@Component, @Service, @Repository, @Controller 등 사용@ComponentScan 을 통해 파일들을 스캔하고 @Component가 붙은 클래스를 확인 하고 등록한다.
주입방법또한 자동방식과 수동방식으로 나뉜다.
@Autowired
private MemberService memberService;
주입할 대상에 @AutoWired 로 판별하여 주입한다.
ApplicationContext 하위의 AnnotationConfigApplicationContext 를 통해 빈을 꺼낼 수 있다.
@Autowired
@Qualifier("mainMemberService")
private MemberService memberService;
@Primary
@Component
public class MainMemberService implements MemberService {}
인터페이스에 해당하는 등록된 클래스가 두개 이상일때는 primary와 qualifier를 통해 명시해야 한다.
| 어노테이션 | 역할 | 내부 구성 |
|---|---|---|
@Component | 모든 Bean의 기본 | 최상위 |
@Repository | 영속성 계층에 특화 | 예외 변환 지원 |
@Service | 서비스 계층 명시 목적 | 특별 기능 없음 (가독성↑) |
@Controller | MVC 컨트롤러 등록 | DispatcherServlet이 인식 |
사용방법은 알아보았으니 실제로 어떤방식으로 동작하는지 궁금하여 찾아보았다.
스프링 doc을 참고하였다.
Spring 컨테이너는 ApplicationContext 인터페이스의 구현체를 통해 동작한다.

1. 설정 정보 로딩 (자바 설정 클래스, XML 등)
2. 클래스패스 스캔 or @Bean 기반 객체 인식
3. BeanDefinition 생성 (메타정보 생성)
4. BeanDefinition 등록 (BeanFactory에 저장)
5. Bean 인스턴스 생성
6. 의존성 주입 (Autowired, Constructor, Setter 등)
7. 초기화 콜백 실행
8. 사용 가능 상태로 컨테이너에 보관
즉 내가 이해한 과정은 다음과 같다.
예: AnnotationConfigApplicationContext(AppConfig.class)
또는 XML 기반에서는 ClassPathXmlApplicationContext("appContext.xml")
| 인터페이스 | 역할 |
|---|---|
BeanFactory | 가장 기본적인 컨테이너. DI만 지원 |
ApplicationContext | BeanFactory 확장판. AOP, 이벤트, 메시지 처리 등 포함 |
AnnotationConfigApplicationContext | 자바 기반 설정을 지원하는 구현체 |
ClassPathXmlApplicationContext | XML 기반 설정을 지원하는 구현체 |
짧게 정리하자면 설정클래스에 명시한 정보를 토대로 BeanDefinition을 생성하여 Beanfactory에 저장해놓고 해당 빈 스코프 생명주기에 따라 실제 빈을 생성한다. 생성한 빈들은 DI작업이 수행될떄 ApplicationContext 내부에 등록된 빈들을 찾아 연결하고 초기화 작업이 실행된 뒤 후에 자유롭게 사용할 수 있는 상태가 된다.
1. 객체 생성 (Constructor)
2. 의존성 주입 (@Autowired)
3. 빈 등록 후 처리 (BeanPostProcessor)
4. 초기화 콜백 (InitializingBean, @PostConstruct)
5. 빈 사용 가능
6. 소멸 콜백 (DisposableBean, @PreDestroy)
| 구분 | 방법 | 설명 |
|---|---|---|
| 초기화 | @PostConstruct | 의존성 주입 완료 후 자동 호출 |
| 초기화 | InitializingBean.afterPropertiesSet() | 수동 구현 가능 |
| 소멸 | @PreDestroy | 컨테이너 종료 전 자동 호출 |
| 소멸 | DisposableBean.destroy() | 수동 구현 가능 |
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 초기화 전 호출
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 초기화 후 호출
return bean;
}
}
| 단계 | 설명 | 실행 시점 |
|---|---|---|
| 생성자 호출 | 객체 생성 | Bean 등록 시 |
| 의존성 주입 | @Autowired, 생성자 | Bean 생성 후 |
| 초기화 콜백 | @PostConstruct, InitializingBean | DI 후 |
| 후처리 | BeanPostProcessor | 초기화 전/후 |
| 소멸 콜백 | @PreDestroy, DisposableBean | 컨테이너 종료 시 |