본문 바로가기
WEB/Spring

[ Spring ] IOC 수업 정리 - (2)

by 방준이 2021. 11. 20.
반응형

[ Spring ] IOC 수업 정리 - (2)

본 글은 KOSTA에서 교육을 들으면서 배웠던 내용을 복습해보고자 블로그에 올리는 글입니다. 지난 수업 정리 - (1)에 이어서 조금 다른 예제로 IOC에 대한 필요성과 이해를 느껴 보고자 합니다.  추가로  DI에 대해서 맛보기로 예제를 살펴보겠습니다. 우선 IOC를 사용하지 않는 방식에 대해서 먼저 살펴보겠습니다.

 

1. 기존 제어방식

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package model;
 
class AsianaTicketService {
    public void asianaTicketing() {
        System.out.println("아시아나 티케팅하다");
    }
}
class KalTicketService {
    public void kalTicketing() {
        System.out.println("대한항공 티케팅하다");
    }
}
public class TestCustomer {
    public static void main(String[] args) {
//        AsianaTicketService service = new AsianaTicketService();
//        service.asianaTicketing();
        
        // 만약 항공사를 변경해야 한다면
        // 다음과 같이 코드를 수정해주어야 한다.
        KalTicketService service = new KalTicketService();
        service.kalTicketing();
    }
}
 
 

 

지난 수업정리-(1)에 이어서 기존의 제어 방식은 위와 같습니다. 저번 시간과는 다른 점은 interface를 활용하지 않고 각각의 도구를 독립적인 클래스로 정의하였습니다. 즉, 계층 구조화가 되어있지 않고 인터페이스를 사용한 방식이 아니므로 컴포넌트(도구)의 변경 시 선언 부도 같이 수정해주어야 합니다. 위에서와 같이 항공사를 변경해야 한다면 선언부와 더불어 코드의 전반적인 부분이 수정되는 것을 볼 수 있습니다. 그렇다면 어제 잠깐 맛봤던 IOC 적용과 더불어 계층 구조화를 통해서 결합을 느슨하게 (Loose Coupling) 만들어 보겠습니다.

 

 

2. 계층구조화 + IOC 방식 적용

- ioc.xml

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="ticket" class="model.KalTicketServiceImpl"></bean>
</beans>
 
 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface TicketService {
    public void ticketing();
}
public class AsianaTicketServiceImpl implements TicketService {
    public void asianaTicketing() {
        System.out.println("아시아나 티케팅하다");
    }
    @Override
    public void ticketing() {
        asianaTicketing();
    }
}
public class KalTicketServiceImpl implements TicketService {
    public void kalTicketing() {
        System.out.println("대한항공 티케팅하다");
    }
 
    @Override
    public void ticketing() {
        kalTicketing();
    }
}
 
 

 

1
2
3
4
5
6
7
8
9
public class TestCustomer2_IOC {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext factory = new ClassPathXmlApplicationContext("ioc.xml");
       
        TicketService service = (TicketService) factory.getBean("ticket");
        service.ticketing();
        factory.close();
    }
}
 

 

위의 코드는 계층구조화와 IOC를 적용한 코드이다. 

 

  1. 컴포넌트 (도구)들의 계층 구조화 형성 : 메서드 즉 소통방식의 표준화
  2. 스프링 설정 (ioc.xml) 을 통해서 ioc container에게 컴포넌트를 생성하도록 지시

 

위의 2가지를 적용함으로써 결합도를 느슨하게 하고 항공사의 서비스 (도구)를 변경하더라도 사용자 측, 클라이언트 측에서는 코드의 변경이 필요하지 않다. 즉 외부의 영향이 최소화가 된다.

 

 

 

3. IOC - DI  예제

지금까지의 예제는 xml 파일에서 단순히 객체를 생성하면 되는 예제였지만 이번 예제에서는 객체를 생성하면서 인스턴스 변수를 초기화 해주어야 하는 예제입니다. 이번 방식에서는 생성자를 정의해 놓고 인스턴스를 초기화하는 방식을 살펴보겠습니다. 파일의 구조는 다음과 같습니다.

 

 

    -  spring-config.xml

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="memberDAO" class="model.MemberDAOImplVer2"></bean>
    <bean id="memberService" class="model.MemberServiceImpl">
        <constructor-arg>
            <ref bean="memberDAO" />
        </constructor-arg>
     </bean>
</beans>
cs

 

    -  MemberServiceImpl .java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MemberServiceImpl implements MemberService {
    // 느슨한 결합도를 위해 인터페이스 타입으로 참조
    private MemberDAO memberDAO;
    // 스프링 IOC (or DI) Container에서 MemberDAO 구현체를 주입 -> Dependency Injection, DI
    public MemberServiceImpl(MemberDAO memberDAO) {
        super();
        this.memberDAO = memberDAO;
    }
    @Override
    public String findMemberById(String id) {
        return memberDAO.findMemberById(id);
    }
}
 
 

   

 TestDI.java

1
2
3
4
5
6
7
8
public class TestDI {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext factory = new ClassPathXmlApplicationContext("spring-config.xml");
        MemberService memberService = (MemberService)factory.getBean("memberService");    // DL (Dependency LookUp)
        System.out.println(memberService.findMemberById("java"));
        factory.close();
    }
}
 
 

 

 

MemberServiceImpl를 코드를 살펴보자 해당 코드에서는 MemberDAO 타입의 인스턴스 변수가 선언되어 있다. 해당 인터페이스를 구현하고 있는 클래스는 그림에도 보이듯이 MemberDAOImpl, MemberDAOImplVer2가 있다. 즉 둘 중에 하나 객체를 넣어주어야 한다. 하지만 main 메서드에서 작업을 하는것이 아니라 xml파일에서 작업하기를 희망한다.

 

1
2
3
4
5
6
<bean id="memberDAO" class="model.MemberDAOImplVer2"></bean>
<bean id="memberService" class="model.MemberServiceImpl">
    <constructor-arg>
        <ref bean="memberDAO" />
    </constructor-arg>
</bean>
 
 

 

위의 코드는 spring-config.xml 파일의 일부분이다. MemberService 클래스에서는 MemberDAO 형 인스턴스 변수를 필요로 한다. 구조를 다시 한번 살펴 보자.

 

 

MemberDAOImpl 혹은 MemberDAOImplVer2 둘중 하나를 넣어주어야 한다. 이 역시 위의 xml 파일에서와 같이 정의를 해주어야 한다. 이는 <constructor-arg> 태그와  <ref bean="memberDAO" /> 를 사용한다. 이 방식을 통해서 스프링 컨테이너를 통해서 MemberDAO의 구현체를 주입한다 이를 DI 라는 표현을 사용해서 표현한다.

반응형

'WEB > Spring' 카테고리의 다른 글

[Spring] IOC 수업정리 - (1)  (0) 2021.11.19