우리는 그전까지는 @Configuration 애너테이션을 통해서 직접 스프링 설정 클래스를 작성해서 스프링 컨테이너에 등록하였다. 이 방법은 설정 클래스의 코드가 너무 길어진다는 단점이 있다.
앞 포스팅에서 설명했듯, @Autowired도 기존에는 생성자나 세터메서드 방식으로 의존 주입하던 방식에서 스프링에서 자동으로 의존 주입을 해준다. 그렇기때문에 설정 클래스의 코드가 더 간결해졌다.
이 @Component 애너테이션도 마찬가지이다. 이 애너테이션을 스프링 빈 객체로 등록하고자 하는 클래스에 붙이면, 스프링 설정클래스(@Configuration) 에서 등록할 필요 없이 스프링이 알아서 등록 해 준다.
예를 들면 기존에는,
@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;
}
}
이렇게 애너테이션을 통해 설정 클래스가 구성되었다. 위에 @Qualifier를 붙인 이유는 두 객체 모두 MemberPrinter 타입을 상속받기 때문에 만약 해당 객체의 타입을 @Autowired를 통해 의존주입해줘야하는 입장이면, @Qualifier한정자를 통해 구별해 줘야 한다. 왜냐하면 같은 타입의 빈 객체가 2개이기 때문이다.
다시 본론으로 돌아와서 이렇게 복잡한 스프링 설정 클래스를 빈객체에 등록하고 싶은 클래스 위에 @Component 를 붙임으로써 간결한 코드로 만들 수 있다.
@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;
}
}
그리고 스프링 설정 클래스에서 @ComponentScan 애너테이션을 사용하면 아래와 같이 @Component 애너테이션이 붙은 클래스들을 자동으로 스프링 빈으로 등록한다.
@Component
public class MemberDao {
private static long nextId = 0;
private Map<String, Member> map = new HashMap<>();
public Member selectByEmail(String email) {
return map.get(email);
}
public void insert(Member member) {
member.setId(++nextId);
map.put(member.getEmail(), member);
}
public void update(Member member) {
map.put(member.getEmail(), member);
}
public Collection<Member> selectAll() {
return map.values();
}
}
위의 클래스처럼 @Compoent 애너테이션에 아무런 값(식별자)를 주지 않으면, 디폴트 값으로는 해당 클래스 이름의 앞글자를 소문자로 한 "memberDao"라는 이름으로 빈에 등록된다. 만약 빈 이름을 명시적으로 지정하고 싶다면 아래와 같이, @Component("infoPrinter") 이렇게 문자열 값을 애너테이션 뒤에 넣어주면 된다.
@Component("infoPrinter")
public class MemberInfoPrinter {
private MemberDao memDao;
private MemberPrinter printer;
public void printMemberInfo(String email) {
Member member = memDao.selectByEmail(email);
if (member == null) {
System.out.println("데이터 없음\n");
return;
}
printer.print(member);
System.out.println();
}
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memDao = memberDao;
}
@Autowired
@Qualifier("printer")
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
}
또 스프링 설정 클래스에서 컴포넌트 스캔을 할때, 스캔 범위를 지정해 주어야 하는데, @ComponentScan( basepackages= {"패키지명"}) 이렇게 값을 주면 해당 패키지명 하위에 있는 모든 패키지와 클래스 파일들을 스캔한다.
만약 이름이 똑같은 스프링 빈이 하나는 @Configuration 설정클래스에서 수동등록, 또 다른 하나는 @Component를 통한 자동등록을 했을때, 수동으로 등록한 빈이 우선적으로 등록되서 결국 스프링 빈으로는 최종적으로 1개의 빈만 등록된다.
하지만 컴포넌트 스캔을 통해 각각 다른 패키지의 같은 이름의 빈을 자동등록하면 문제가 생긴다. 두 객체가 같은 이름으로 등록된다는 익셉션이 나오는데, 이때는 @Component("식별자") 이렇게 빈 이름을 다르게 함으로써 해결 할 수 있다.
*요약 하자면,
같은 빈 이름 으로 2개의 객체를 자동 등록-> 애러남.
다른 빈 이름으로 2개의 같은 타입의 객체를 수동등록 -> 의존주입할때 @Qualifier로 구별.
'기록 > Spring framework' 카테고리의 다른 글
스프링 웹 개발 입문(인프런 강의 요약). 2021-12-14 (0) | 2021.12.14 |
---|---|
빈 라이프 사이클. InitializingBean, DiposableBean. 2021-11-29 (0) | 2021.11.29 |
@Autowired의 스프링 빈 필수여부( null 값 전달.), 의존 자동주입과 수동주입의 우선순위. 2021-11-18 (2) | 2021.11.18 |
의존 자동주입 할때 타입이 일치하는 빈 중 의존 주입할 대상 빈을 선택하는 방법: @Qualifer 이용법. 2021-11-12 (0) | 2021.11.12 |
자동 의존 주입 @Autowired 의 실질적 적용 (세터 메서드, 필드). 2021-11-11 (0) | 2021.11.11 |