ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java Spring] IoC, DI (의존성 주입 방법 xml, annotation)
    Programming/Java 2022. 10. 30. 03:39
    반응형

    IoC(Inversion of Control), 제어의 역전

    : 객체 생성을 프레임워크가 유연하게 제어함으로써 객체간 결합도를 줄여, 유연성 증가, 코드 중복 제어, 유지 보수의 편리성 증가

    - 스프링이 모든 의존성 객체를 스프링이 실행될 때 다 만들어주고 필요한 곳에 주입
    - Bean들은 싱글턴 패턴의 특징을 가지며, 제어의 흐름을 사용자가 컨트롤하지 않고 스프링에게 맡겨 작업 처리

    [ 일반적인 객체 제어 과정 ]
    1. 객체 생성
    2. new 키워드를 통해 의존성 객체 생성(클래스 내부에서 생성)
    3. 의존성 객체의 메소드 호출
    [ 스프링의 객체 제어 과정 ]
    1. 객체 생성
    2. 의존성 객체 주입 (스프링이 만들어놓은 객체를 주입)
    3. 의존성 객체의 메소드 호출

    DI (Dependency Injection), 의존성 주입

    : 외부에서 두 객체간의 관계를 결정해줌으로써, 클래스 레벨에서 의존관계가 고정되지 않고 런타임시 관계를 동적으로 주입 → 유연성 확보 및 결합도 감소

    [ 의존성 주입을 하지 않았을 경우 ]

    컴퓨터를 1대 판매하는 Store 클래스가 있다고 할 때, 보통의 객체 생성은 아래와 같은 방법으로 가능

    // 강한 결합
    // Store클래스는 Computer 클래스에 의존함
    
    /* 문제점
    * 1. 강한 결합으로 인해 Computer가 아닌 다른 상품을 판매하고 싶다면, 생성자 변경이 필요 -> 유연성 감소, 유지보수 어려움
    * 2. 객체 간 관계가 아닌 클래스 간 관계가 맺어짐으로써 객체 지향 프로그래밍에서 멀어짐
    */
    
    public class Store {
    
      private Computer computer; // 
      
      public Store() {
        this.computer = new Computer();
      }
    }

    [ 의존성 주입을 할 경우 ]

    다형성의 원리에 의해, Computer 등의 상품을 하나로 묶어줄 Interface 생성하여 Store가 인터페이스를 통해 실제 객체를 주입받도록 함
    - Spring에서는 애플리케이션 실행 시점에 필요한 객체(빈)을 생성하여 의존성이 있는 두 객체를 연결하기 위해 한 객체를 다른 객체로 주입시켜주는 역할을 해 줌
    ※ Spring IoC 컨테이너가 관리하는 자바 객체를 빈(Bean)이라고 하며, ApplicationContext에 해당 객체가 만들어져야 의존성 주입을 할 수 있음

    // 상품들을 묶어줄 Product 인터페이스 생성
    public interface Product {
    
    }
    
    // Product 인터페이스를 implement한 클래스
    public class Computer implements Product {
    
    }
    
    public class Labtop implements Product {
    
    }
    
    public class Store {
      
      private Product product;
     
      // 어떤 물건을 팔지 외부에서 상품을 주입 받아야 함
      public Store(Product product) {
        this.product = product;
      }
    }

    Spring IoC Container

    : Bean의 객체화 조립, 관리, 사용 소멸에 대한 처리 담당
    - Bean Factory: 프레임워크 설정과 기본 기능을 제공하는 컨테이너, 모든 유형의 객체 관리 가능한 메커니즘 제공
    - ApplicationContext: BeanFactory 하위 인터페이스로 이벤트 처리, 국제화용 메시지처리, AOP 통합 기능 제공
    - WebApplicationContext: 웹 환경에서 Spring을 사용하기 위한 기능 추가. 대표적 구현 클래스로 XmlWebApplicationContext가 있음

    의존성 주입 방법

    1. Bean 생성 및 설정

    1-1. xml 방식

    : xml 파일에 모든 bean 객체를 등록하고, 의존관계를 설정해주는 방법

     

    - id: 스프링 컨테이너에서 사용할 bean 고유의 식별자
    - class: 객체화할 객체의 클래스 전체 경로 (정규화된 자바 클래스 이름)
    - scope: 객체의 범위 (기본 singleton이며 prototype 설정시에는 객체 주입시마다 새로운 객체를 생성함)

    - constructor-arg: 생성時 생성자에 전달할 인수

    - property: 생성時 bean setter에 전달할 인수

    // 기존 자바코드 방식의 의존성 생성 과정
    
    // 0. Exam 객체 생성
    Exam exam = new MidtermExam();
    
    // 1. 생성자를 통해 결합
    ExamConsole console = new InlineExamConsole(exam);
    
    // 2. setter를 통해 결합
    ExamConsole console = new InlineExamConsole();
    console.setExam(exam);
    
    // 스프링 프레임워크를 통한 의존성 주입 과정
    // xml파일에 bean객체들 생성 후 주입.
    
    // 0. Exam 빈 객체 생성
    <bean id="exam" class="spring.di.entity.MidtermExam" />
    
    // 1. 생성자를 통해 의존성 주입
    <bean id="console" class="spring.di.ui.InlineExamConsole">
      <constructor-arg ref="exam" />
    </bean>
    
    // 2. setter를 통해 의존성 주입
    <bean id="console" class="spring.di.ui.InlineExamConsole">
      // name 뒤는 setExam을 의미, ref 뒤는 의존성 주입 대상 빈 객체의 id를 의미
      <property name="exam" ref="exam" />
    </bean>

    1-2. Annotation 방식

    : xml 파일에는 Bean등록을 위한 대상 패키지만 설정하고 객체를 생성할 대상 클래스에 어노테이션 표시를 하는 방법

     

    - @Component: 스프링에서 관리되는 객체임을 표시하기 위해 사용되는 가장 기본적 annotation
    ※ Component의 기능을 좀 더 명확하게 하기 위해 명시적으로 아래와 같이 분리 사용함 (aspect에 연관성 부여)
    - @Controller: 클라이언트로부터 요청이 왔을 때 지정된 뷰에 모델 객체를 넘겨주는 역할
                             즉, 요청에 따라 어떤 처리를 할지 결정하여 service에 넘겨주고 service가 처리한 내용을 view에 넘김

    - @Service: 비즈니스 로직이나 repository layer를 호출하는 함수에 사용. 비즈니스 로직을 수행 결과를 Controller에 넘김

    - @Repository: 외부 DB에 접근하는 코드(DAO)

    - @Autowired: 의존성을 주입할 대상 위에 작성(xml에서는 constructor-arg, property 태그로 명시

    - @Qualifier: 주입 대상이 두 개 이상이거나 빈 객체일 경우, bean을 지정하여 식별 가능하게끔 함

     

    - 어노테이션 방식의 경우, 생성되는 bean 객체의 이름은 클래스 첫 글자를 소문자로 바꾼 것
      임의 지정하고 싶다면 @Component(value="bean-name")형태로 지정 가능

    // xml파일에 Annotation으로 Bean을 등록할 대상 패키지 설정
    <context:component-scan base-package="spring.di.*" />
    // 각 클래스에 어노테이션을 붙여 Bean객체로 만듦
    @Component
    public class MidtermExam implements Exam {
    ...
    }
    
    @Service
    public class InlineExamConsole implements ExamConsole {
    
      @Autowired // 의존성 주입할 대상에 작성
      private Exam exam;
      
      ...
    }

    2. 스프링 컨테이너 객체 생성

    - main함수에서 스프링 컨테이너 생성 후, 빈 객체 가져온 후 사용 가능

    public class Test {
      public static void main(String[] args) {
        Application context context = new GenericXmlApplicationContext("spring/di/applicationContext.xml"); // xml설정파일이 있는 주소
        ExamConsole console = context.getBean(ExamConsole.class);
        console.print();
      }
    }

     

    반응형

    댓글

Designed by Tistory.