컴포넌트 스캔이란?
스프링이 직접 클래스를 검색해서 빈으로 등록해주는 기능이다.
설정 클래스(AppCtx클래스)에 빈으로 등록하지 않아도 원하는 클래스를 빈으로 등록할 수 있으므로 컴포넌트 스캔 기능을 사용하면 설정 코드가 크게 줄어든다.
package spring;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.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();
}
}
package spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("infoPrinter")
public class MemberInfoPrinter {
private MemberDao memDao;
private MemberPrinter printer;
...
}
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;
}
}
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;
}
}
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"},
excludeFilters = @Filter(type = FilterType.REGEX, patter = "spring\\..*Dao" ))
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;
}
}
@Configuration
@ComponentScan(basePackage = {"spring"},
excludeFilters = @Filter(type = FilterType.ASPECTJ, pattern = "spring.*Dao"))
public class AppCtxWithExclude {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
}
@Configuration
@ComponentScan(basePackage = {"spring", "spring2"},
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = {NoProduct.class, ManualBean.class}))
public class AppCtxWithExclude {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
}
@Configuration
@ComponentScan(basePackage = {"spring"},
excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MemberDao.class))
public class AppCtxWithExclude {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
}
@Configuration
@ComponentScan(basePackages = {"spring"},
excludeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = ManualBean.class ),
@Filter(type = FilterType.REGEX, pattern = "spring2.\\..*")
})
public class AppCtxWithExclude {
@Component 애노테이션을 붙인 클래스만 컴포넌트 스캔 대상에 포함되는 것은 아니다.
기본이 되는 대상
- @Component
- @Controller
- @Service
- @Repository
- @Aspect
- @Configuration
spring패키지와 spring2패키지에 MemberRegisterService 클래스가 모두 존재하고 @Component 애노테이션을 모두 붙였다면?
@Configuration @ComponentScan(basePackages = {"spring", "spring2"}) public class AppCtx { ... }
- spring2 패키지의 MemberRegisterService클래스를 빈으로 등록할 때 기존의 spring패키지의 동일한 클래스 빈이름 과 충돌이난다.
- 이런 경우 둘중 하나를 수동으로 @ComponentScan("registerService") 이런식으로 변경해주어서 빈(빈객체)이름 충돌을 피해준다.
자동으로 빈 등록 하는 방법
@Component public class MemberDao {//명시적으로 변경하지 않았기 때문에 빈(빈객체) 이름은 memberDao로 생성된다.
}
> 수동으로 빈을 등록하는 방법
```java
@Configuration
@ComponentScan(basePackages = {"spring", "spring2" })
public class AppCtxWithExclude {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
}
자동으로 빈 등록 하는 방법
@Component public class MemberDao {//명시적으로 변경하지 않았기 때문에 빈(빈객체) 이름은 memberDao로 생성된다.
}
> 수동으로 빈 등록 하는 방법
```java
@Configuration
@ComponentScan(basePackages = {"spring"})
public class AppCtxWithExclude {
@Bean
public MemberDao memberDao2() {
MemberDao memberDao = new MemberDao();
return memberDao;
}
}