Spring DI 흉내내기-(3)

개발세발·2024년 2월 13일

객체를 자동 연결하기

  • @Autowired(by Type) 어노테이션을 사용

  • 자동으로 인스턴스 변수에 선언된 타입에 맞는 값을 연결해줌.

  • @Resource(by Name) 어노테이션을 사용

  • 인스턴수 변수에 선언된 타입의 첫글자를 소문자로 바꾼 이름을 찾아 값을 연결해줌.

package com.fastcampus.ch3.diCopy4;

import com.google.common.reflect.ClassPath;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Component
class Car{
  @Resource
  Engine engine;
  @Autowired
  Door door;

  @Override
  public String toString() {
      return "Car{" +
               "engine=" + engine +
                ", door=" + door +
                '}';
    }
}
@Component class sportCar extends Car{}
@Component class Truck extends Car{}
@Component class Engine{}
@Component class Door{}
class AppContext{
    Map map;

    AppContext() {
        map = new HashMap();
        doComponentScan();
        doAutoWired();
        doResource();
    }

    private void doResource() {
        //map에 저장된 객체의 인스턴스 변수에 @Resource 붙어 있으면
        //map에서 iv의 이름에 맞는 객체를 찾아서 연결(객체의 주소 인스턴스 변수에 저장)
        for(Object bean: map.values()){
            try {
                for(Field fld: bean.getClass().getDeclaredFields()){
                    if((fld.getAnnotation(Resource.class)!=null)){ //by Name
                        fld.set(bean, getBean(fld.getName()));
                    }
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void doComponentScan() {
        try {
            // 1. 패키지 내의 클래스 목록을 가져온다.
            // 2. 반복문으로 클래스를 하나씩 읽어와서 @Component이 붙어 있는지 확인
            // 3. @Component가 붙어 있으면 객체를 생성해서 map에 저장
            ClassLoader classLoader = AppContext.class.getClassLoader();
            ClassPath classPath = ClassPath.from(classLoader);

            Set<ClassPath.ClassInfo> set = classPath.getTopLevelClasses("com.fastcampus.ch3.diCopy4");
            for(ClassPath.ClassInfo classInfo : set) {
                Class clazz = classInfo.load();
                Component component = (Component)clazz.getAnnotation(Component.class);
                if(component!=null){
                    String id = StringUtils.uncapitalize(classInfo.getSimpleName());
                    map.put(id, clazz.newInstance());
                }

            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    Object getBean(String key){return map.get(key);}

    Object getBean(Class clazz){ //byname
        for (Object obj: map.values()){
            if(clazz.isInstance(obj)){
                return obj;
            }
        }
        return null;
    }

    private void doAutoWired(){
        //map에 저장된 객체의 인스턴스 변수에 @Autowired가 붙어 있으면
        //map에서 iv의 타입에 맞는 객체를 찾아서 연결(객체의 주소 인스턴스 변수에 저장)
        for(Object bean: map.values()){
            try {
                for(Field fld: bean.getClass().getDeclaredFields()){
                    if((fld.getAnnotation(Autowired.class)!=null)){
                        fld.set(bean, getBean(fld.getType()));
                    }
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class main4 {
    public static void main(String[] args) throws Exception {
        AppContext ac = new AppContext();
        Car car = (Car)ac.getBean( "car");
        Car car2 = (Car)ac.getBean(Car.class);
        Engine engine = (Engine)ac.getBean("engine");
        Door door = (Door) ac.getBean(Door.class);
        System.out.println("car = " + car);
        System.out.println("car2 = " + car2);
        System.out.println("engine = " + engine);
        System.out.println("door = " + door);

    }


}

내용

  • doAutowired()
  1. map에 저장된 객체의 인스턴스 변수에 @Autowired가 붙어 있으면
  2. map에서 iv의 타입에 맞는 객체를 찾아서 연결(객체의 주소 인스턴스 변수에 저장)
  • doResource()
  1. map에 저장된 객체의 인스턴스 변수에 @Resource 붙어 있으면
  2. map에서 iv의 이름에 맞는 객체를 찾아서 연결(객체의 주소 인스턴스 변수에 저장)

0개의 댓글