yunyj99
라둥이
yunyj99
GitHub
전체 방문자
오늘
어제
  • 분류 전체보기 (309)
    • 1. 프로그래밍 (50)
      • 1-1. Git (17)
      • 1-2. Java (13)
      • 1-2-1. Java GUI (1)
      • 오류 (12)
      • 기타 (7)
    • 2. Front-end (57)
      • 2-1. HTML (5)
      • 2-2. CSS (19)
      • 2-3. Java Script (33)
      • 2-4. React (0)
    • 3. Back-end (47)
      • 3-1. Spring MVC - 국비 (15)
      • 3-2. Spring MVC - 남궁성 (30)
      • 3-3. Spring - 김영한 (2)
    • 4. Android (1)
    • 5. DB (20)
      • 4-1. MySQL DBMS (20)
    • 6. 자료구조 & 알고리즘 (44)
      • 6-1. 자료구조 (14)
      • 6-2. 백준 (30)
    • 7. 웹 디자인 (7)
      • 7-1. UX 디자인 (7)
    • 8. 자격증 (35)
      • 8-1. 정보처리기사 (35)
    • 프로젝트 (3)
      • 프로젝트 기록 (3)
    • etc... (43)
      • 패스트캠퍼스 챌린지 (39)
      • 잡담 (4)

블로그 메뉴

  • 홈
  • 태그

최근 글

티스토리

hELLO · Designed By 정상우.
yunyj99

라둥이

쓰기
3. Back-end/3-2. Spring MVC - 남궁성

Spring MVC - [ Spring DI ]

2023. 2. 8. 03:43

1. 변경에 유리한 코드(1) - 다형성, factory method

아래와 같이 코드를 작성하면 SportsCar를 Truck으로 변경할 때 변경해야 할 포인트는 2군데이다.

SportsCar car = new SportsCar();

Truck car = new Truck();

다형성을 이용하면 변경 포인트를 한 군데로 줄일 수 있다.

Car car = new SportsCar();

Car car = new Truck();

그리고 아래처럼 메서드로 반환받을 경우, 객체를 생성하는 코드는 손 댈 필요가 없고 메서드에서 반환 타입만 변경해주면 된다.

Car car = getCar();
static Car getCar() {
	return new SportsCar();
}

static Car getCar() {
	return new Truck();
}

 

 

 


2. 변경에 유리한 코드(2) - Map과 외부 파일

아래와 같이 파일에서 클래스 정보를 받아오는 경우, 파일만 변경하고 코드는 변경하지 않아도 된다. 프로그램의 변경을 최소화 한다는 것은 엄청난 장점이다.

Car car = getCar();

static Car getCar() throws Exception {
    // config.txt를 읽어서 properties에 저장
    Properties p = new Properties();
    p.load(new FileReader("config.txt"));
    
    // 클래스 설계(설계도)를 얻어서
    Class clazz = Class.forName(p.getProperty("car"));
    
    return (Car)clazz.newInstance(); // 객체를 생성해서 반환
}
[config.txt]
car = com.fastcampus.ch3.SportsCar

Properties는 Map과 비슷하다고 보면 된다. config.txt 파일을 로드하면 Key(car) : Value(com.fastcampus.ch3.SportsCar) 와 같이 값이 들어간다고 생각하면 됨

 

아래와 같이 Object타입으로 변경하면 조금 더 확장해서 사용할 수 있다.

Car car = (Car)getObject("car");
Engine engine = (Engine)getObject("engine");

static Object getObject(String key) throws Exception {
    // config.txt를 읽어서 properties에 저장
    Properties p = new Properties();
    p.load(new FileReader("config.txt"));
    
    // 클래스 설계(설계도)를 얻어서
    Class clazz = Class.forName(p.getProperty(key));
    
    return clazz.newInstance(); // 객체를 생성해서 반환
}
[config.txt]
car = com.fastcampus.ch3.SportsCar
engine=com.fastcampus.ch3.Engine

 

 

 

 


3.객체 컨테이너(ApplicationContext) 만들기

class AppContext {
    // Map이 객체 저장소 = 객체 컨테이너 역할
    Map map;
    
    AppContext() {
        // 하드코딩 했을 경우 
        /*
        map = new HashMap();
        map.put("car", new SportsCar()); 
        map.put("engine", new Engine());
        */
        
        // properties 이용해 불러오기 
        Properties p = new Properties();
        p.load(new FileReader("config.txt");
        // config.txt 파일 map에 저장
        // properties는 (String, String)  Map은 (String, Object)
        map = new HashMap(p); 
        
        for(Object key : map.keySet()) {
            Class clazz = Class.forName((String)map.get(key)); // 클래스 이름 가져오기
            map.put(key, clazz.newInstance()); // 객체 생성해서 map에 저장
        }
    }

    Object getBean(String id) { return map.get(id); }
}
AppContext ac = new AppContext();
Car car = (Car)ac.getBean("car");
Engine engine = (Engine)ac.getBean("engine");

 

 

 


4. 자동 객체 등록 - Component Scanning

클래스 앞에 @Component 애노테이션을 붙이고, Properties를 이용해 외부 파일에서 클래스 이름을 불러와 map에 객체 인스턴스를 담는 코드를 아래와 같이 바꿀수 있다.

즉, @Component 애노테이션이 붙은 클래스들은, map안에 객체명의 첫 글자를 소문자로 바꾼 단어를 key로 해서 담기게 된다. 따로 외부파일에 클래스 정보를 작성할 필요가 없다. (보통은 config.txt 파일에 공통 객체를 지정하고 개인이 만든 클래스 파일에 @Component 애노테이션을 붙인다.)

=> Component Scanning : 애노테이션을 이용해서 객체 저장소에 저장할 빈들을 지정해 주는 것

@Component class Car {}
@Component class SportsCar extends Car {}
@Component class Truck extends Car {}
@Component class Engine {}
// -- guava 라이브러리 이용 --

ClassLoader classloader = AppContext.class.getClassLoader();
ClassPath classPath = ClassPath.from(classloader);

// 패키지 내의 모든 클래스를 읽어서 Set에 저장
Set<ClassPath.ClassInfo> set = classPath.getTopLevelClasses("com.fastcampus.ch3");

for(ClassPath.ClassInfo classInfo : set) { // 패키지 내에 @Component 붙은 클래스 찾아서 자동으로 등록
    Class clazz = classInfo.load();
    Component component = (Component)clazz.getAnnotation(Component.class);
    if(component!=null) ( // 만약 Component 애노테이션 붙어있으면
        String id = StringUtils.uncapitalize(classInfo.getSimpleName()); // Car -> car (클래스 이름만 가져와 소문자로 변경)
        map.put(id, clazz.newInstance()); // 객체 생성해서 map에 저장
    }
}

 

 

 


5. 객체 찾기 - by Name, by Type

객체를 찾을 때 이름으로 찾는 걸 by Name, 타입으로 찾는 걸 by Type 이라고 한다.

AppContext ac = new AppContext();
Car car = (Car)ac.getBean("car"); //이름(id)으로 찾기
Car car2 = (Car)ac.getBean(Car.class); //타입으로 찾기
// 이름으로 찾기
// = map에서 key값에 해당하는 값 찾아서 반환
Object getBean(string id) { 
	return map.get(id);
}

// 타입으로 찾기
// = map의 value에서 해당하는 인스턴스 찾아서 반환
Object getBean(Class clazz) {// 타입으로 찾기
	for (Object obj : map.values()) {
		if (clazz.isInstance(obj)) // obj instanceof clazz
		return obj;
	}
	return null;
}

 

 

 


6. 객체 자동 연결 (1) - @Autowired

만약 아래와 같은 Car 클래스가 있다면, 

class Car {
	Engine engine;
	Door door;
}

수동으로  멤버변수로 있는 Engine과 Door에 객체를 생성해서 값을 줘야한다.

AppContext ac = new AppContext();
Car car = (Car)ac.getBean("car");
Engine engine = (Engine)ac.getBean("engine");
Door door = (Door)ac.getBean("door");

car.engine = engine;
car.door = door;

 

그러나 @Autowired 애노테이션을 사용하면 map에서 byType형식으로 객체를 찾아 자동 연결시켜준다.

* Autowired는 타입으로 먼저 검색 후, 여러개일 경우 이름으로 검색해서 찾는다.

class Car {
    @Autowired Engine engine;
    @Autowired Door door;
}

 

 

 


6. 객체 자동 연결(2) - @Resource

@Resource도 마찬가지로 객체를 자동으로 연결시키는 애노테이션인데 by Name 즉 이름으로 찾아준다는 점이 @Autowired와 다르다. 찾을 땐 클래스 이름의 첫글자를 소문자로 바꾼값을 key로 map에서 찾는다.

class Car {
    @Resource Engine engine; // 사실은 @Resource(name="engine") 임. 뒷부분은 생략되어있음
    @Resource Door door;
}



class Car {
    @Resource(name="engine2") Engine engine; // 혹은 다른 이름 직접 지정해도 OK
    @Resource Door door;
}

 


참조

https://fastcampus.co.kr/dev_academy_nks

 

스프링의 정석 : 남궁성과 끝까지 간다 | 패스트캠퍼스

국비지원 조기 마감 신화, 베스트셀러 'JAVA의 정석'의 저자 남궁성의 Spring 강의입니다! 오픈톡방과 카페에서 평생 AS를 제공하며 완강과 취업까지 도와드립니다. 지금 할인가로 확인하세요!

fastcampus.co.kr

 

'3. Back-end > 3-2. Spring MVC - 남궁성' 카테고리의 다른 글

Spring MVC - [ AOP ]  (0) 2023.03.09
Spring MVC - [ Transaction, commit, Rollback ]  (0) 2023.03.03
Spring MVC - [ 데이터의 검증 ]  (0) 2023.02.02
Spring MVC - [ 데이터의 변환 ]  (0) 2023.02.02
Spring MVC - [ DispatcherServlet ]  (0) 2023.02.01
    '3. Back-end/3-2. Spring MVC - 남궁성' 카테고리의 다른 글
    • Spring MVC - [ AOP ]
    • Spring MVC - [ Transaction, commit, Rollback ]
    • Spring MVC - [ 데이터의 검증 ]
    • Spring MVC - [ 데이터의 변환 ]
    yunyj99
    yunyj99
    개발자를 목표로 하는, 새싹처럼 성장하고 싶은 사람의 학습 공간 ^v^

    티스토리툴바