5. 컴포넌트 스캔
컴포넌트 스캔
스프링이 직접 클래스를 검색해서 빈으로 등록해주는 기능이다.
@Component 애노테이션으로 스캔 대상 설정
- @Component를 붙여주면 해당 클래스를 스캔 대상으로 설정한다.
- 값을 부여하면 해당 값으로 이름을 결정하고 값이 없을 경우 클래스 이름의 첫글자를 소문자로 바꾼 이름을 지정한다.
@ComponentScan 애노테이션으로 스캔 설정
- @Component를 붙인 클래스를 스캔해서 스프링 빈으로 등록하려면 설정 클래스에 @ComponentScan을 적용해야한다.
- basePackages = {"packages"}
- 스캔 대상 패키지 목록을 지정한다, packages패키지와 그 하위 패키지에 속한 클래스를 스캔 대상으로 설정한다.
- excludeFilters = @Filter(type = ,patteren = " ")
- 스캔 대상에서 제외할 대상을 설정한다
@ComponentScan 기본 스캔 대상
- @Component, @Controller, @Service, @Repository, @Aspect, @Configuration 모두 스캔 대상이 된다.
컴포넌트 스캔에 따른 충돌 처리
빈 이름 충돌
- A 패키지와 B 패키지에 모두 C 클래스가 존재하고, A, B 패키지 모두 @Component가 붙어있을때
- @ComponentScan을 하면 같은 이름의 빈이 등록될 수 없어서 충돌이 발생한다.
- 이런 문제는 컴포넌트 스캔 과정에서 쉽게 발생 -> 명시적으로 빈 이름을 지정해서 충돌 방지
수동 등록한 빈과 충돌
- 이전에는 수동 등록 빈이 우선 순위를 가졌지만
- 스프링 부트2.1 이후 부터 Exception이 발생한다.
6. 빈 라이프사이클과 범위
컨테이너 초기화와 종료
스프링 컨테이너는 초기화와 종료라는 라이프사이클을 갖는다.
// 1. 컨테이너 초기화
AnnotaionConfigApplicationContext ctx = new AnnotaionConfigApplicationContext(AppContext.class);
// 2. 컨테이너에서 빈 객체를 구해서 사용
Greeter g = ctx.getBean("greeter", Greeter.class);
String msg = g.greet("스프링");
Sysytem.out.println(msg);
// 3. 컨테이너 종료
ctx.close();
위 코드와 같이 AnnotaionConfigApplicationContext 객체를 생성하고, 스프링 컨테이너를 초기화한다.
스프링 컨테이너는 설정 클래스에서 정보를 읽어와 알맞은 빈 객체를 생성하고 각 빈을 연결(의존주입)한다.
이후 컨테이너가 초기화가 되면 getBean()과 같은 함수들을 통해 컨테이너를 사용할 수 있다.
컨테이너 사용이 끝나면 컨테이너를 종료한다.
컨테이너를 초기화 하고 종료 할때 다음과 같은 작업도 함께 수행된다.
- 컨테이너 초기화 : 빈 객체의 생성, 의존 주입, 초기화
- 컨테이너 종료 : 빈 객체의 소멸
스프링 빈 객체의 라이프 사이클
객체 생성 → 의존 설정 → 초기화 → 소멸
스프링 컨테이너를 초기화 할때 빈 객체를 생성하고 의존을 설정한다. 의존 자동 주입을 통한 의존 설정이 이 시점에 수행된다.
모든 의존 설정이 완료되면 빈 객체의 초기화를 수행한다. 빈 객체를 초기화하기 위해 스프링은 빈 객체의 지정된 메서드를 호출한다.
스프링 컨테이너를 종료하면 스프링 컨테이너는 빈 객체의 소멸을 처리한다. 이때도 마찬가지로 지정한 메서드를 호출한다.
빈 객체의 초기화와 소멸 - 스프링 인터페이스
스프링의 인터페이스인 InitializingBean와 DisposableBean를 받아
InitializingBean의 afterPropertiesSet()를 구현해서 실행, DisposableBean의 destroy()를 구현해서 실행한다.
각각 생성과 주입이 끝난뒤, 소멸 과정에서 해당 함수를 실행한다.
단점
- 해당 인터페이스는 스프링 전용 인터페이스다. 해당 코드가 스프링 전용 인터페이스에 의존한다,
- 초기화, 소멸 메서드의 이름을 변경할 수 없다.
- 내가 코드를 고칠 수 없는 외부 라이브러리에 적용할 수 없다.
빈 객체의 초기화와 소멸 - 커스텀 메서드
스프링 인터페이스 방법의 단점에서 말한것처럼 모든 클래스가 InitializingBean, DisposableBean 인터페이스를 상속받아 구현할 수 있는것이 아니다.
직접 구현한 클래스가 아닌 외부에서 제공받은 클래스를 스프링 빈 객체로 설정하고 싶을 때도 있다.
이런 경우 @Bean 태그에서 initMethod 속성과 destoryMethod 속성을 사용해서 초기화 메서드와 소멸 메서드의 이름을 지정하면 된다.
public class Client{
private String host;
public void setHost(String host){
this.host = host;
}
public void connect(){
System.out.println("Client.connect() 실핼");
}
public void setHost(){
System.out.println("Client.send() to " + host);
}
public void close(){
System.out.println("Client.close() 실핼");
}
}
@Bean(initMethod = "connect", destoryMethod = "close")
public Client client(){
Client client = new Client();
client.setHost("host");
return client;
}
위 코드 처럼 @Bean의 속성값에 초기화와 소멸 과정에서 사용할 메서드의 이름을 적어준다.
특징
- 메서드의 이름을 자유롭게 지정할 수 있다.
- 스프링 빈이 스프링 코드에 의존하지 않는다
- 코드가 아니라 설정 정보처럼 사용하기 때문에 코드를 고칠수 없는 외부 라이브러리에서도 초기화, 종료 메서드를 적용할 수 있다
종료메서드 추론 기능
- @Bean의 destroyMethod 속성에는 아주 특별한 기능이 존재한다.
- close , shutdown 라는 이름의 메서드를 자동으로 호출해준다. 이름 그대로 종료 메서드를 추론해서 호출해준다.
- 따라서 직접 스프링 빈으로 등록하면 종료 메서드는 따로 적어주지 않아도 잘 동작한다.
- 추론 기능을 사용하기 싫으면 destroyMethod="" 처럼 빈 공백을 지정하면 된다.
빈 객체의 초기화와 소멸 - @PostConstruct, @PreDestory
추가적으로 책에는 없지만 추천하는 방법인 @PostConstruct, @PreDestory에 대해 정리를 하겠다.
@PostConstruct : 생성이 된 이후에
@PreDestory : 소멸이 되기 전에
특징
- 최신 스프링에서 가장 권장하는 방법이다.
- 애노테이션 하나만 붙이면 되므로 매우 편리하다.
- 자바 표준이다. 따라서 스프링이 아닌 다른 컨테이너에서도 동작한다.
- 컴포넌트 스캔과 잘 어울린다.
- 유일한 단점은 외부 라이브러리에는 적용하지 못한다는 것이다. 외부 라이브러리를 초기화, 종료 해야 하면 @Bean의 기능을 사용하자.
빈 객체의 생성과 관리 범위
스프링 컨테이너는 빈 객체를 한 개만 생성한다고 했다. (싱글톤)
Client client1 = ctx.getBean("client", CLient.class):
Client client2 = ctx.getBean("client", CLient.class):
// client1 == client2
//true
하지만 빈을 등록 할때 빈의 범위를 프로토타입으로 지정하면 빈 객체를 구할 때마다 매번 새로운 객체를 생성한다.
Client client1 = ctx.getBean("client", CLient.class):
Client client2 = ctx.getBean("client", CLient.class):
// client1 == client2
//false
// client1 != client2
//true
프로토타입으로 지정하는 방법은 다음과 같다.
@Bean
@Scope("Prototype")
Public Client client(){
return client;
}
'Java , Spring > Spring' 카테고리의 다른 글
[Spring] @Controller 와 @RestController (0) | 2023.08.07 |
---|---|
스프링 MVC 1 - 서블릿 servlet (2) (0) | 2023.07.02 |
초보 웹 개발자를 위한 스프링 5 프로그래밍 입문 - 4장 의존 자동 주입 (0) | 2023.05.19 |
초보 웹 개발자를 위한 스프링 5 프로그래밍 입문 - 2장, 3장 (0) | 2023.05.16 |
빈 스코프 (0) | 2023.05.07 |
댓글