참고 자료 : 초보 개발자를 위한 스프링5 프로그래밍 입문
<Chapter5. 컴포넌트 스캔>
1. 컴포넌트 스캔
: 스프링이 직접 클래스를 검색해서 빈으로 등록해주는 기능
즉, 설정 클래스에 빈으로 등록하지 않아도
원하는 클래스를 빈으로 등록할 수 있도록 하는 기능이다.
@Component는 해당 클래스를 스캔 대상으로 표시하며
클래스에 해당 어노테이션을 붙여줘야만
빈으로 등록해야하는 대상으로 인식된다.
// 1
@Component
public class MemberListPrinter{
private MemberDao memberDao;
private MemberPrinter printer;
}
// 2
@Component("listPriner")
public class MemberListPrinter{
private MemberDao memberDao;
private MemberPrinter printer;
}
어노테이션에 값을 안 준 경우에는
memberListPrinter와 같이
클래스 이름의 첫 글자를 소문자로 바꾼 이름을
빈 이름으로 사용한다.
listPrinter처럼 어노테이션에 값을 주었다면
해당 값을 빈 이름으로 사용하게 된다.
만약 해당 클래스를 스캔하여 스프링 빈으로 등록하고자 한다면
설정 클래스에도 @ComponentScan이라는 어노테이션을 붙여줘야한다.
// 4장. AppCtx.java
package config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import spring.MemberPrinter;
import spring.MemberSummaryPrinter;
import spring.VersionPrinter;
@Configuration
@ComponentScan(basePackages = {"spring"})
public class AppCtx {
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
@Qualifier("summaryPrinter")
public MemberSummaryPrinter memberPrinter2() {
return new MemberSummaryPrinter();
}
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5);
versionPrinter.setMinorVersion(0);
return versionPrinter;
}
}
spring 패키지와 그 하위 패키지에 속한 클래스를
스캔 대상으로 설정한다.
package config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.ChangePasswordService;
import spring.MemberDao;
import spring.MemberInfoPrinter;
import spring.MemberListPrinter;
import spring.MemberPrinter;
import spring.MemberRegisterService;
import spring.MemberSummaryPrinter;
import spring.VersionPrinter;
@Configuration
public class AppCtx {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService();
}
@Bean
public ChangePasswordService changePwdSvc() {
return new ChangePasswordService();
}
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
@Qualifier("summaryPrinter")
public MemberSummaryPrinter memberPrinter2() {
return new MemberSummaryPrinter();
}
@Bean
public MemberListPrinter listPrinter() {
return new MemberListPrinter();
}
@Bean
public MemberInfoPrinter infoPrinter() {
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
return infoPrinter;
}
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5);
versionPrinter.setMinorVersion(0);
return versionPrinter;
}
}
2. 빈을 구하는 코드
(1) 속성값이 지정되어 있던 경우
MemberRegisterService regSvc=ctx.getBean("memberRegSvc",MemberRegisterService.class);a
(2) 속성값이 따로 지정이 안되어 있는 경우
MemberRegisterService regSvc=ctx.getBean(MemberRegisterService.class);
3. 스캔 대상에서 제외하거나 포함하는 법
(1) 자동 등록 대상에서 제외하기 : excludeFilters 속성 사용
package config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import spring.MemberDao;
import spring.MemberPrinter;
import spring.MemberSummaryPrinter;
import spring.VersionPrinter;
@Configuration
@ComponentScan(basePackages = {"spring", "spring2" },
excludeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = ManualBean.class )
})
public class AppCtxWithExclude {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
@Qualifier("summaryPrinter")
public MemberSummaryPrinter memberPrinter2() {
return new MemberSummaryPrinter();
}
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5);
versionPrinter.setMinorVersion(0);
return versionPrinter;
}
}
1. FilterType.REGEX
@ComponentScan(basePackages={"spring"},
excludeFilters=@Filter(type=FilterType.REGEX, pattern="spring\\..*Dao"))
=> FilterType.REGEX : 정규표현식을 사용해서 제외 대상을 지정한다는 것을 의미함.
spring.MemberDao 클래스를 컴포넌트 스캔 대상에서 제외한다는 의미이다.
즉 spring 패키지에서 이름이 Dao로 끝나는 타입을
컴포넌트 스캔 대상에서 제외한다.
2. FilterType.ASPECTJ
> 정규표현식 대신 AspectJ 패턴을 사용하여 대상을 지정한다.
단, 의존 대상에 aspectjweaver 모듈을 추가해야 함.
@ComponentScan(basePackages={"spring"},
excludeFilters=@Filter(type=FilterType.ASPECTJ, pattern="spring.*Dao"))
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
4. 기본 스캔 대상
: 해당 어노테이션을 붙인 클래스가 컴포넌트 스캔 대상에 포함된다.
@Component
@Controller
@Service
@Repository
@Aspect
@Configuration
5. 컴포넌트 스캔에 따른 충돌 처리
> 스캔할 때 사용하는 빈 이름과 수동 등록한 빈 이름이 같을 경우,
수동 등록한 빈이 우선되어진다.
<Chapter 6. 빈 라이프사이클과 범위 >
1. 컨테이너 초기화와 종료
// 1. 컨테이너 초기화 (AnnotationConfigApplicationContext 생성자를 이용해서 컨텍스트 객체 생성)
AnnotationConfigApplicationContext ctx=
new AnnotationConfigApplicationContext(AppContext.class);
// 2. 컨테이너에서 빈 객체를 구해서 사용
// 컨테이너를 사용한다 == 메서드를 이용해 컨테이너에 보관된 빈 객체를 구한다는 것을 의미함.
Greeter g= ctx.getBean("greeter",Greeter.class);
String msg=g.greet("스프링");
System.out.println(msg);
// 3. 컨테이너 종료
ctx.close();
컨테이너 초기화 = 빈 객체의 생성, 의존 주입, 초기화
컨테이너 종료 = 빈 객체의 소멸
2. 스프링 빈 객체의 라이프사이클
: 스프링 컨테이너는 빈 객체의 라이프사이클을 관리한다.
객체 생성 -> 의존 설정 -> 초기화 -> 소멸
(1) 빈 객체의 초기화와 소멸 : 스프링 인터페이스
> 스프링 컨테이너는 빈 객체를 초기화하고 소화하기 위해
빈 객체의 지정한 메서드를 호출함.
InitializingBean(초기화 과정 시), DisposableBean(소멸 과정시)
해당 두 인터페이스에 이 메서드를 정의하고 있다.
초기화 및 소멸 과정이 필요한 경우
: 데이터베이스 커넥션 풀, 채팅 클라이언트
[1] InitializingBean, DisposableBean 인터페이스를 구현한 간단한 클래스 작성
package spring;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class Client implements InitializingBean, DisposableBean {
private String host;
public void setHost(String host) {
this.host = host;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Client.afterPropertiesSet() 실행");
}
public void send() {
System.out.println("Client.send() to " + host);
}
@Override
public void destroy() throws Exception {
System.out.println("Client.destroy() 실행");
}
}
[2] Client 클래스를 위한 설정 클래스
package config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.Client;
import spring.Client2;
@Configuration
public class AppCtx {
@Bean
public Client client() {
Client client = new Client();
client.setHost("host");
return client;
}
@Bean(initMethod = "connect", destroyMethod = "close")
public Client2 client2() {
Client2 client = new Client2();
client.setHost("host");
return client;
}
}
[3] Main.java
> AppCtx를 이용해서 스프링 컨테이너를 생성하고
Client 빈 객체를 구해 사용하는 코드
package main;
import java.io.IOException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import config.AppCtx;
import spring.Client;
public class Main {
public static void main(String[] args) throws IOException {
AbstractApplicationContext ctx =
new AnnotationConfigApplicationContext(AppCtx.class);
Client client = ctx.getBean(Client.class);
client.send();
ctx.close();
}
}
(2) 빈 객체의 초기화와 소멸 : 커스텀 메서드
@Bean 태그에서 initMethod 속성과 destroyMethod 속성을 사용하여
초기화 및 소멸 메서드의 이름을 지정하는 방식은
해당 두 인터페이스를 사용하고 싶지 않거나 구현할 수 없는 상황에서 사용할 수 있는 방법이다.
3. 빈 객체의 생성과 관리 범위
: 스프링 컨테이너는 빈 객체를 한 개만 생성한다고 배웠다.
동일한 이름을 갖는 빈 객체를 구하면 A와 B는 동일한 빈 객체를 참조한다.
따라서 별도의 설정을 하지 않으면 빈은 싱글톤 범위를 갖는다.
사용빈도가 낮지만 프로토타입 범위의 빈을 설정할 수도 있다.
빈 객체를 구할 때마다 매번 새로운 객체를 생성하게 된다.
@Configuration
public class AppCtxWithPrototype {
@Bean
@Scope("prototype")
public Client client() {
Client client = new Client();
client.setHost("host");
return client;
}
}
만약, 싱글톤 범위를 명시적으로 지정하고싶으면
@Scope 의 값을 prototype => singleton으로 변경하면 된다.
단, 프로토타입 범위를 갖는 빈은
완전한 라이프사이클을 따르지 않는다는 점에 주의해야 한다.
따라서 빈 객체의 초기화까지는 수행하나
소멸 메서드는 실행하지 않으므로
빈의 소멸처리를 직접 코드에 작성해야 한다.
'여니의 프로그래밍 study > Spring & Spring Boot' 카테고리의 다른 글
[Spring] DB 연동 - 1(Chapter 8) (1) | 2023.09.16 |
---|---|
[Spring] AOP 프로그래밍 (Chapter 7) (0) | 2023.09.03 |
[Spring] 의존 자동 주입 (Chapter 4) (0) | 2023.08.12 |
[Spring] 스프링 DI (의존, 의존주입, 조립기) - 2 (0) | 2023.08.06 |
[Spring] 스프링 DI (의존, 의존주입, 조립기) - 1 (0) | 2023.07.23 |