Component Scanning이란 스프링에서 @Component가 붙은 클래스를 자동으로 검색(스캔)하여 Bean으로 등록하는 기능이다.
이는 XML 설정 없이 스프링이 직접 클래스를 찾아서 관리할 수 있도록 해준다.
guava를 사용하기 때문에 maven repository에 들어가서 의존성을 복사해 pom.xml에 추가해줘야한다. (사전 작업 필요)
@Component
public class SportsCar {
public void drive() {
System.out.println("스포츠카 주행 중...");
}
}
@Component를 붙이면 스프링이 자동으로 객체를 관리한다.
@Configuration
@ComponentScan(basePackages="")
public class AppConfig{}
""안에 있는 패키지에서 @Component가 붙은 클래스를 찾아서 자동으로 Bean 등록을 해준다.
applicationContext.xml파일에 아래 코드를 넣어준다.
<context:component-scan base-package="com.example" />
"com.example" 패키지에 자동으로 Bean을 등록해준다는 의미이다.
@Component class Car{}
@Component class SportsCar extends Car{}
@Component class Truck extends Car{}
@Component class Engine{}
class AppContext{
Map map;
AppContext(){
map = new HashMap();
doComponentScan();
}
private void doComponentScan() {
try {
//1. 패키지 내의 클래스 목록을 가져옴
ClassLoader classLoader = AppContext.class.getClassLoader();
ClassPath classPath = ClassPath.from(classLoader);
Set<ClassPath.ClassInfo> set = classPath.getTopLevelClasses("com.fastcampus.ch3.diCopy3");
//2. 반복문으로 클래스를 하나씩 읽어와서 @Component가 붙어있는지 확인
for(ClassPath.ClassInfo classInfo : set) {
Class clazz = classInfo.load();
Component component = (Component) clazz.getAnnotation(Component.class);
//3. 붙어있으면 객체를 생성해서 맵에 저장
if(component != null) {
String id = StringUtils.uncapitalize(classInfo.getSimpleName());
map.put(id,clazz.newInstance());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Object getBean(String key){
return map.get(key);
}
}
public class Main3 {
public static void main(String[] args) throws Exception {
AppContext ac = new AppContext();
Car car = (Car)ac.getBean("car");
System.out.println("car: "+car);
Engine engine = (Engine)ac.getBean("engine");
System.out.println("engine: "+engine);
}
}
패키지 내의 클래스 목록을 불러온다.
ClassLoader를 선언하여 클래스를 메모리에 불러온다.
ClassPath를 선언해서 classLoader에서 불러온 클래스의 경로를 저장한다.
getTopLevelClasses 메서드를 활용하여 특정 패키지에 속한 최상위 클래스를 가져온다.
반환되는 객체를 Set<ClassPath.ClassInfo> 형태의 Set에 저장한다.
여기에는 해당 패키지에 있는 모든 클래스의 정보(이름, 경로 등)가 포함되어 있기 때문에 패키지 내에 어떤 클래스가 존재하는지 확인이 가능하다.
반복문으로 클래스를 하나씩 읽어와 @Component가 붙어있는지 확인
Class형의 clazz에 클래스의 정보를 불러와 담는다.
그 후 clazz.getAnnotaion 메서드를 사용하여 @Component가 붙어있는지 확인한다.
여기서 getAnnotation 메서드는 주어진 어노테이션이 붙어있는 경우 객체를 반환하고, 붙어있지 않은 경우 null값을 반환한다.
어노테이션이 붙어있으면 객체 생성 후 맵에 저장
위에서 getAnnotation을 한 결과가 null이 아니면 즉, @Component 어노테이션이 붙어있으면 클래스의 이름을 소문자로 변환하여 저장한다.
(StringUtils.uncapitalize())
그 후 map에 key와 객체(생성)를 저장한다.