안녕하세요. 이번에 포스팅 할 내용은 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는 생성자를 이용하여 주입
- property는 setter메소드를 사용하여 주입
<?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 |