스프링 컨테이너 : 애플리케이션의 구성 요소를 생성 및 관리
> 개발자가 직접 객체를 생성하고 관리하는 부담을 줄여줌
> 스프링 빈을 생성하고 의존 관계를 주입하는 역할
Bean (스프링 빈) : 스프링 컨테이너가 관리하는 객체
스프링 컨테이너에 의해 생명 주기가 관리됨
제어 역전 (IoC) / 의존성 주입 (DI) 기능
Bean의 정의와 역할
스프링의 객체 !
Spring IoC 컨테이너에 의해 인스턴스화되고 관리됨
애너테이션 추가 / XML 파일 설정을 통해 Bean이 선언됨
** MyBean 클래스에 @Component 애너테이션을 붙이면 클래스가 빈으로 등록됨
** 빈의 이름은 클래스 이름의 첫 글자를 소문자로 바꾸어 관리 → myBean으로 등록됨
다양한 역할 수행
- 데이터 액세스 계층의 리포지토리
- 웹 요청을 처리하는 컨트롤러
- 서비스 계층의 비즈니스 로직
- ...
> Spring 컨테이너는 이러한 Bean들을 생성하고, 의존성 주입을 통해 서로 연결시켜줌
Bean의 설정
1. XML 설정에서의 빈 식별자와 별칭 지정 방법
빈 아이디, 빈 이름 : 특정 빈을 구분해서 가리키기 위한 빈 식별자(identifier)
빈은 하나 또는 그 이상의 식별자를 가질 수 있음 > id, name 속성을 동시에 지닐 수 있음
** id는 문서 전체에서 고유해야 하며, name은 여러 개를 지정할 수 있음
** 하나 이상의 빈 name을 부여할 때는 콤마(,)나 세미콜론(;)을 이용하여 구분
<bean name="1234,/hello;헬로우" class="...">
** 빈의 이름을 여러 개를 주면 같은 빈이지만 다른 이름으로 참조할 수 있음
2. 애노테이션을 이용한 빈 지정 방법
1) @Component와 같은 스테레오 타입의 애노테이션을 부여
→ 빈 스캐너에 의해 자동 인식되어 빈으로 등록됨
** 클래스 이름을 그대로 빈 이름으로 사용하면서 첫 글자만 소문자로 바꾸어 자동등록됨
** UserService에 @Component 부여 → userService라는 이름의 빈 자동 등록
2) 애노테이션을 이용하지만 직접 빈 이름 지정
→ 스테레오 타입 애노테이션의 디폴트 엘리먼트 값으로 이름을 지정
@Component("myUserService")
public class UserService{
}
@Component
@Named("myUserService")
public class UserService{
}
3) @Configuration 애노테이션이 달린 클래스에 @Bean 애노테이션을 붙인 메소드 생성
@Configuration
public class Config{
@Bean
public UserDto userDto(){
}
}
** 메소드 이름이 그대로 빈 이름이 됨
** userDto라는 이름의 빈 생성
Bean의 생명주기
1. 생성 (Initialization)
- 인스턴스화 : Spring 컨테이너가 Bean 정의를 바탕으로 객체의 인스턴스를 생성
- 의존성 주입 : 생성된 Bean에 필요한 의존성을 주입 (생성자 주입 / setter 주입 / 필드 주입)
- 초기화 콜백 : 컨테이너는 Bean의 초기화 작업을 수행
- InitializingBean 인터페이스를 구현한 afterPropertiesSet 메소드 호출
- XML 구성의 init-method 호출
- @PostConstruct 애너테이션이 붙은 메소드 호출
2. 사용 (Running)
- 사용 단계에서의 Bean은 완전히 초기화되어 있음
- 애플리케이션에서 필요로 할 때마다 Spring 컨테이너로부터 주입받아 사용됨
3. 파괴 (Destruction)
- 종료 콜백 : 애플리케이션 종료 / 컨테이너 종료 시점에 Bean의 정리 과정이 시작됨
- DisposableBean 인터페이스를 구현한 destroy 메소드 호출
- XML 구성의 destroy-method 호출
- @PreDestroy 애너테이션이 붙은 메소드 호출
- Bean이 사용한 자원을 해제하고 필요한 종료 작업을 수행
- 소멸 : 모든 종료 콜백이 실행된 후 Bean 인스턴스는 가비지 컬렉션의 대상이 되어 시스템에서 제거됨
ex 1)
서비스 클래스 MyService 정의
이 클래스의 객체가 생성될 때 / 소멸될 때 실행될 메소드에 @PostConstruct / @PreDestroy 애너테이션 지정
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class MyService {
public MyService() {
System.out.println("MyService 인스턴스 생성");
}
@PostConstruct
public void init(){
// 초기화 작업
System.out.println("MyService 초기화 작업 실행");
}
public void serviceMethod(){
// 서비스 메소드 실행 로직
System.out.println("MyService의 serviceMethod 실행");
}
@PreDestroy
public void destroy(){
// 소멸 전 처리 작업
System.out.println("MyService 소멸 전 처리 작업 실행");
}
}
Spring의 구성 파일 (applicationContext.xml) 또는 Java 구성 클래스를 사용하여 MyService를 Bean으로 등록
Java 기반의 구성 > @Configuration 애너테이션 사용하여 구성 클래스 정의
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig{
@Bean
public MyService myService(){
return new MyService();
}
}
Spring 애플리케이션 실행하여 실행 중에 MyService Bean의 serviceMethod를 호출
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main{
// Spring 컨테이너 생성 및 구성 클래스 등록
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// Bean 가져오기 및 메소드 호출
MyService myService = context.getBean(MyService.class);
myService.serviceMethod();
// 컨테이너 종료
context.close();
}
→ Bean 인스턴스 생성 (생성자)
→ @PostConstruct 애너테이션 붙은 init 메소드
→ myServiceMethod
→ @PreDestroy 애너테이션 붙은 destroy 메소드
→ 컨테이너 종료
ex 2)
애너테이션을 통한 Bean 등록 / 초기화 콜백 등록 / 종료 콜백 등록
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class LoginService {
private UserAuthenticationManager authenticationManager;
public LoginService() {
// 기본 생성자
}
@PostConstruct
public void init() {
// 로그인 서비스 관련 초기화 작업
this.authenticationManager = new UserAuthenticationManager();
// 필요한 초기 데이터 로드 또는 초기화 로직 실행
System.out.println("LoginService 초기화 완료. 필요한 자원을 로드하였습니다.");
}
public boolean login(String username, String password) {
// 사용자 인증 로직 구현
return authenticationManager.authenticate(username, password);
}
@PreDestroy
public void cleanup() {
// 로그인 서비스 종료 전 자원 정리 작업
// 예를 들어, 캐시된 사용자 데이터를 정리하거나, 외부 시스템과의 연결을 해제
System.out.println("LoginService 종료 중. 사용된 자원을 정리합니다.");
}
}
ex 3)
InitializingBean, DisposableBean 인터페이스를 구현하여 초기화 콜백, 종료 콜백 등록
afterPropertiesSet 메소드, destroy 메소드를 오버라이딩
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
@Aspect
@Slf4j
@Getter
public class FactorialLoggingAspect implements InitializingBean, DisposableBean {
private boolean isInitialized;
private boolean isDestroyed;
@Override
public void afterPropertiesSet() throws Exception{
isInitialized = true;
log.info("FactorialLoggingAspect Bean initialized");
}
@Override
public void destroy() throws Exception{
isDestroyed = true;
log.info("FactorialLoggingAspect Bean destroyed");
}
@Pointcut("execution(public void com.elice.factorial..factorial(..))")
private void targetMethod() {};
@Before("targetMethod()")
public void logBefore(JoinPoint joinPoint) {
log.info("[메서드 호출 전] 호출 클래스: " + joinPoint.getTarget().getClass().getSimpleName());
log.info("[메서드 호출 전] 호출 메서드: " + joinPoint.getSignature().getName());
}
@After("targetMethod()")
public void logAfter(JoinPoint joinPoint) {
log.info("[메서드 호출 후] 호출 메서드: " + joinPoint.getSignature().getName());
}
}
'spring' 카테고리의 다른 글
타임리프(Thymeleaf) (0) | 2024.09.13 |
---|---|
템플릿 엔진(Template Engine) (0) | 2024.09.13 |
MVC 패턴 (0) | 2024.04.20 |
HTTP / REST API (0) | 2024.04.19 |
스프링 프레임워크 / Spring Boot (1) | 2024.04.19 |