본문으로 바로가기

DI(Dependency injection) 의존 주입

category JAVA/Spring 2019. 11. 27. 13:46
반응형


안녕하세요. 이번에 포스팅 할 내용은 DI입니다.
저는 DI를 스프링 수업시간에 잠깐 배웠다가 면접 질문으로 많이 나온다는 이야기를 듣고 더 공부했던적이,, 있습니다.

DI 란

 

의존성 주입을 의미합니다. 

의존성이란 하나의 객체를 사용하고 있는걸 뜻합니다. 밑에 그림을 보면서 설명하겠습니다.

 

 

일체형 배터리와 분리형 배터리 차이

 

1. 일체형 배터리는 배터리를 다 사용하면 사용 불가능 합니다.
2. 분리형 배터리는 배터리를 다 사용하면 교체만 하면 사용 가능 합니다.

 

위 두가지 차이점은 배터리가 분리되어 있으면 결합도가 낮아진다는 내용이 됩니다. DI를 사용하는 목적도 같습니다.

 

결합도가 낮아지면 좋은점


1. 단위테스트가 수월해짐.          
2. 코드가 단순해짐.                   
3. 컴포넌트 간의 결합도가 제거됨.  *컴포넌트 : 독립적인 단위모듈
4. 유연성이 높아짐. 

 

 

스프링 DI 설정 방법

 

스프링 컨테이너 생성 및 빈(Bean)객체 호출 과정

  • applicationContext.xml을 이용하여 DI 설정
    • property는 setter메소드를 사용하여 주입
      • name → 메소드명(set 지우고 앞글자는 소문자로)
      • value → 매개변수 값 
      • list 타입일 경우 <list></list> 붙이고 안에 value사용
      • map 타입일 경우 <map></map> 붙이고 안에 <key><value>키값</value></key>     ,     <value>값</value>
    • constructor-arg는 생성자를 이용하여 주입

 

<?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="studentDao" class="ems.member.dao.StudentDao"></bean>

     

    <!-- setter을 이용하여 주입방법 -->

    <bean id="myInfo" class="com.test.MyInfo">

        <property name="name" value='임광민'/>

        <property name="height" value=187/>

        <property name="weight" value=60/>

        <property name="hobbys">

            <list>

                <value>게임</value>

                <value>요리</value>

                <value>잠</value>

            </list>

        </property>

        <property name="bmiCalculator">

            <ref bean="bmiCalculator" />

        </property>

    </bean>

 

    <!-- 생성자를 이용한 주입방법 -->

    <bean id="myInfo2" class="com.text.MyInfo">

        <constructor-arg value="임광민" />

        <constructor-arg value="187" />

        <constructor-arg value="60" />

        <constructor-arg>

            <list>

                <value>게임</value>

                <value>요리</value>

            </list>

        </constructor-arg>

    </bean>

</beans>

 

DI를 이용한 객체(Bean) 호출

 

//더이상 StudentDAO stdao = new StudentDAO()를 사용하지 않고

//GenericXmlApplicationContext와 applicationContext.xml을 이용하여 스프링 컨테이너를 만듬.

GenericXmlApplicationContext ctx =  new GenericXmlApplicationContext("classpath:applicationContext.xml");

 

//getBean을 사용하여 스프링 컨테이너에서 가지고 온다.

StudentModifyService modifyService  = ctx.getBean("modifyService", StudentModifyService.class);

스프링 설정 파일

  • appCtx1 ~ appCtx3 처럼 각 기능 별로 xml을 구분지어 만들어서 사용

 

//사용하려면 다 선언해줘야함

GenericXmlApplicationContext ctx1 = new GenericXmlApplicationContext("classpath:appCtx1.xml");

GenericXmlApplicationContext ctx2 = new GenericXmlApplicationContext("classpath:appCtx2.xml");

GenericXmlApplicationContext ctx3 = new GenericXmlApplicationContext("classpath:appCtx3.xml");

 

//3개를 배열로 넣어서 한번에 선언

String[] appCtxs = {"classpath:appCtx1.xml", "classpath:appCtx2.xml", "classpath:appCtx3.xml"};

GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(appCtxs);

 

//import해서 사용

//xml에서 import를 하여 하나만 선언

<import resource="classpath:appCtx1.xml"/>

<import resource="classpath:appCtx2.xml"/>

 

//선언

GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:appCtx3.xml");

 

 

Bean의 범위

싱클톤

  • 스프링 컨테이너에서 생성된 Bean 객체의 경우 동일한 타입에 대해서는 기본적으로 한개만 생성됨.
  • getBean() 메소드로 호출될 떄 동일한 객체가 반환됨.
  • 새로운 객체를 만들려면???? 
    • 프로토타입(Prototype) 사용 안했을떄

----------------------------------------------------------------------------------------------------------------

//XML

<bean id="dependencyBean" class="scope.ex.DependencyBean">

    <constructor-arg ref="injectionBean" />

    <property name="injectionBean" ref="injectionBean" />

</bean>

 

----------------------------------------------------------------------------------------------------------------

//JAVA

GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationContext.xml");

         

InjectionBean injectionBean = ctx.getBean("injectionBean", InjectionBean.class);

         

DependencyBean dependencyBean01 = ctx.getBean("dependencyBean", DependencyBean.class);

         

DependencyBean dependencyBean02 = ctx.getBean("dependencyBean", DependencyBean.class);

         

if(dependencyBean01.equals(dependencyBean02)) {

    System.out.println("dependencyBean01와 dependencyBean02는 같다");

} else {

    System.out.println("dependencyBean01와 dependencyBean02는 다르다");

}

 

//결과 값 : dependencyBean01와 dependencyBean02는 같다

 

  • 프로토타입(Prototype) 사용했을떄

 

//XML

<bean id="dependencyBean" class="scope.ex.DependencyBean" scope="prototype">

    <constructor-arg ref="injectionBean" />

    <property name="injectionBean" ref="injectionBean" />

</bean>

 

----------------------------------------------------------------------------------------------------------------

//JAVA

GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationContext.xml");

         

InjectionBean injectionBean = ctx.getBean("injectionBean", InjectionBean.class);

         

DependencyBean dependencyBean01 = ctx.getBean("dependencyBean", DependencyBean.class);

         

DependencyBean dependencyBean02 = ctx.getBean("dependencyBean", DependencyBean.class);

         

if(dependencyBean01.equals(dependencyBean02)) {

    System.out.println("dependencyBean01와 dependencyBean02는 같다");

} else {

    System.out.println("dependencyBean01와 dependencyBean02는 다르다");

}

 

//결과 값 : dependencyBean01와 dependencyBean02는 다르다

 

의존 객체 자동 주입이란?

스프링 설정 파일에서 의존 객체를 주입할 떄 <constructor-org> 또는 <property>태그로 의존 대상 객체를 명시하지 않아도 스프링 컨테이너가 자동으로 필요한 의존 대상 객체가 필요한 객체에 주입해 주는 기능이다. 구현 방법은 @Autowired와 @Resource 어노테이션을 이용해서 쉽게 구현할 수 있다.

 

@Autowired

  • 의존 주입 용도의 어노테이션
  • 타입을 참조함
    • 동일한 객체가 2개 이상인 경우 스프링 컨테이너는 자동 주입 대상 객체를 판단못해 Exception을 발생시킴
    • @Qualifier 사용
  • 프로퍼티 메소드 생성자 사용 가능

 

  • <context:annotation-config> 를 적어야 의존 주입 가능
  • qualifier을 사용하면 동일한 객체가 2개 인경우 @Autowired로 bean을 부를때 Exception이 발생하지 않음

 

<?xml version="1.0" encoding="UTF-8"?>

 

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:context="http://www.springframework.org/schema/context"

    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

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context.xsd">

 

    <context:annotation-config />

 

    <bean id="wordDao1" class="com.word.dao.WordDao" >

        <qualifier value="usedDao"/>

    </bean>

    <bean id="wordDao2" class="com.word.dao.WordDao" />

     

    <bean id="registerService" class="com.word.service.WordRegisterServiceUseAutowired" />

     

    <bean id="searchService" class="com.word.service.WordSearchServiceUseAutowired" />

     

</beans>

 

  • @Autowired는 프로퍼티 생성자 메소드를 사용가능
  • 생성자에 @Autowired를 사용하지 않을경우 default 생성자를 만들어야함

 

package com.word.service;

 

public class WordRegisterServiceUseAutowired {

 

    @Autowired

    @Qualifier("usedDao")

    private WordDao wordDao;

     

    public WordRegisterServiceUseAutowired() {

        // TODO Auto-generated constructor stub

    }

     

    @Autowired

    public WordRegisterServiceUseAutowired(WordDao wordDao) {

        this.wordDao = wordDao;

    }

     

    public void register(WordSet wordSet) {

        String wordKey = wordSet.getWordKey();

        if(verify(wordKey)) {

            wordDao.insert(wordSet);

        } else {

            System.out.println("The word has already registered.");

        }

    }

     

    public boolean verify(String wordKey){

        WordSet wordSet = wordDao.select(wordKey);

        return wordSet == null ? true : false;

    }

     

    @Autowired

    public void setWordDao(WordDao wordDao) {

        this.wordDao = wordDao;

    }

     

}

 

@Response

  • 의존 주입 용도의 어노테이션
  • 이름을 참조함
  • 프로퍼티 또는 메소드 사용가능
    • default 생성자를 만들어줘야함 

 

@Inject

  • @Autowired와 비슷하지만 @Inject는 require 속성을 지원하지 않아서 의존 대상 객체가 없으면 에러가 발생한다.
    • require 속성은 @Autowired에서 의존 객체를 사용했는데 xml파일에 없을 경우 Exception을 피하는 방법입니다. (별로 사용하지는 않음)
  • qualifier와 동일하게 Named가 있음.

 

※궁금하신 점은 댓글로 남겨주세요

※공감이 되셨다면 공감 버튼도 눌러주세요

반응형

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

톰켓 다운로드 및 이클립스 서버 설정하기  (0) 2020.03.01
Spring을 Eclipse에 설치하기  (0) 2020.02.29
SPRING 외부 접근  (0) 2019.10.12
SPRING 포트 충돌  (0) 2019.10.12
pom.xml 첫줄 에러  (0) 2019.10.12