티스토리 뷰

자동차에서 만약 엔진이 오래되서 엔진을 바꾸고 싶다면, 자동자 전체가 아닌 엔진만 뽑아서 바꿔주면 됩니다. 객체 지향 프로그래밍에서도 클래스에 대한 변경이 필요하면 다른 클래스에 영향을 끼치지 않으면서 변경이 가능해야 합니다. 이러한 상황에 더 수월하게 변경이 가능케 도와줄수 있도록 도입된 기능이 바로 DI(Dependency Injection)IoC(Inversion of Control)입니다.

 

 

자바로 프로그래밍을 하면서 객체를 생성할 때 직접 클래스에 new 연산자를 이용하여 생성했습니다. 하지만 DI는 개발자가 직접 코딩을 하여 객체를 생성하는 것이 아니라, 컨테이너가 이를 생성시켜 주는 것입니다. 그렇게 된다면 코드에서 직접적인 연관 관계가 발생하지 않아 각 클래스들의 변경이 자유로워 집니다. 이를 느슨한 결합이라고 합니다.

 

각 클래스들간 결합도가 높게되면 나중에 프로젝트가 복잡해질시 유지보수가 힘들게 됩니다. 따라서 각 클래스들간 연관 관계를 클래스 자체 내에서 맺어주는 것이 아니라 스프링 자체에서 설정을 통해 연관 관계를 맺어줌으로써 결합도를 낮춰줍니다.

 

클래스의 변경 사항이 연속적으로 다른 클래스에 영향(자바코드에서 직접 객체를 생성하여 사용하는 것)을 미친다면 좋은 방법은 아닙니다.

 

public class BoardServiceImpl implements BoardService{
	BoardDAO boardDAO;
	public BoardService() {
		boardDAO = new BoardOracleDAOImpl(); //=> 클래스에서 직접 생성
	}
}

 

인터페이스를 이용하여 각 클래스를 구현하면 그나마 클래스들 간 의존 관계가 약해지지만, 만약 오라클이 아닌 Mysql 로 하고 싶다면, 아래와 같이 하면 되는데, 이럴 경우 여전히 계속 클래스 자체에서 new 이용하여 클래스 객체를 생성시켜줍니다.

 

public class BoardServiceImpl implements BoardService{
	BoardDAO boardDAO;
	public BoardService() {
		//boardDAO = new BoardOracleDAOImpl(); //=> 클래스에서 직접 생성
        boardDAO = new BoardMySqlDAOImpl();
	}
}

 


l DI를 해야하는 이유

 

DI를 사용했을 때의 장점입니다.

  • 클래스들 간 의존 관계를 최소화 할 수 있다.
  • 프로젝트 유지보수가 용이하다.
  • 기존에는 개발자가 직접 객체의 생성과 소멸을 제어했는데 DI로 인해 객체의 생성과 소멸 등 클래스간 의존관계를 스프링 컨테이너가 제어해준다.

DI는 객체의 생성, 소멸, 의존 관계를 개발자가 직접 설정하는 것이 아니라 XML이나 애너테이션을 통해 스프링 프레임워크가 제어합니다. 기존에는 개발자가 직접 객체를 생성해줬던 반면에 스프링 프레임워크에서는 객체의 제어를 스프링이 직접 담당해주는 IoC 특징을 가집니다.

 

스프링이 직접 객체를 주입해줍니다.

 

스프링에서는 의존하는 객체를 컨테이너 실행 시 객체를 주입하기 때문에 DI라고 부릅니다. 여기서 각 클래스 객체를 Bean(이하 빈)이라고 부르는데 이는 의존관계를 설정하는 xml 파일에서 각각의 객체를 <bean> 태그로 표시하기 때문입니다.

 

스프링에서 의존 객체를 주입하는 방법은 두가지가 있습니다.

  • setter를 이용한 방법
  • 생성자를 이용한 방법

이 2가지에 대한 예시를 보여드리겠습니다.

 

<bean> 태그의 속성들

속성 이름 설명
id 빈 객체의 고유이름으로, 이를 이용하여 빈에 접근하며 중복되서 안된다.
name 빈 객체의 별칭
class 생성할 클래스 이름 (빈 객체를 주입할 클래스의 이름 )
constructor-arg 생성자를 이용해 값을 주입할 때 사용한다.
property setter를 이용해 값을 주입할 때 사용한다.

l setter를 이용한 방법

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
                             "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
	<bean id="personService" class="com.spring.ex01.PersonServiceImpl">
	<!-- id는 빈의 고유이름, class는 객체 주입할 클래스 이름 -->
		<property name="name">
			<value>홍길동</value>
		</property>
		<property name="blood">
			<value>A형</value>
		</property>
	</bean>
</beans>

 

new를 이용해 직접 객체를 생성하던 것을 person.xml에 설정한 것입니다.

 

package com.spring.ex01;

public interface PersonService {
	public void sayHello();
}
package com.spring.ex01;

public class PersonServiceImpl implements PersonService{
	private String name;
	private int age;
	private String blood;
	
	/*
	 * xml <value> 태그의 값을 setter 이용해 설정
	 * setter 안해주면 에러뜸
	 * 만약 여기 클래스에 blood에 관한 변수가 없어도
	 * 빈즈에서 property로 blood를 생성해주면
	 * 그에 대한 setter가 반드시 있어야함
	 * setter 말고 생성자로도 설정 가능
	 * */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * setter의 인자로 빈에서 생성한 클래스 객체를 넣어줌으로써
	 * 객체를 주입했기 때문에 DI라고 할수 있다.
	 * @param blood
	 */
	public void setBlood(String blood) {
		this.blood = blood;
	}
	
	@Override
	public void sayHello() {
		System.out.println(this.name);
		System.out.println(this.blood);
		System.out.println(this.age);
	}
}

 

PersonServiceImpl에서 인터페이스 PersonService를 구현하고 setter를 이용해 person.xml에서 <value> 태그로 설정한 값을 name 속성에 주입합니다.

 

package com.spring.ex01;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class PersonTest {
	public static void main(String[] args) {
		BeanFactory factory = new XmlBeanFactory(new FileSystemResource("person.xml"));
		// person.xml 파일을 불러와 BeanFactory 객체를 생성시켜줍니다. 즉 빈을 생성시킴
		PersonService person = (PersonService) factory.getBean("personService");
		//person.xml에서의 빈 객체의 id를 가져와줍니다. id는 고유이름이므로 중복되지 않습니다.
		
		
		//PersonService person = new PersonServiceImpl(); 
		// 더이상 자바 코드에서 객체를 직접 생성하지 않아도 된다.
		
		person.sayHello();
	}
}

 

실행 클래스를 실행하면 스프링의 XmlBeanFactory 클래스를 이용해 person.xml의 설정대로 PersonServiceImpl 빈을 메모리에 생성합니다.

 

출력 결과


ㅣ 생성자를 이용한 방법

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
                             "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
	<bean id="personService1" class="com.spring.ex02.PersonServiceImpl">
	<!-- id는 빈의 고유이름, class는 객체 주입할 클래스 이름 -->
		<constructor-arg value="이순신"></constructor-arg>
	</bean>
	
	<bean id="personService2" class="com.spring.ex02.PersonServiceImpl">
		<constructor-arg value="손흥민"></constructor-arg>
		<constructor-arg value="28"></constructor-arg>
	</bean>
</beans>

 

xml에서 property 대신 constructor-arg를 이용하여 value 를 설정해줍니다.

 

package com.spring.ex02;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

import com.spring.ex01.PersonService;

public class PersonTest2 {
	public static void main(String[] args) {
		BeanFactory factory = new XmlBeanFactory(new FileSystemResource("person2.xml"));
		// person.xml 파일을 불러와 BeanFactory 객체를 생성시켜줍니다.
		PersonService2 person1 = (PersonService2) factory.getBean("personService1");
		//person.xml에서의 빈 객체의 id를 가져와줍니다. id는 고유이름이므로 중복되지 않습니다.
		
		PersonService2 person2 = (PersonService2) factory.getBean("personService2");
		
		//  PersonService person = new PersonServiceImpl(); 더이상 자바 코드에서
		// 객체를 직접 생성하지 않아도 된다.
		
		person1.sayHello();
		person2.sayHello();
	}
}

 

setter와 똑같이 해주면 됩니다.

 

출력 결과


l 요약

 

  • DI는 클래스들간 의존관계를 낮추기 위해 사용됩니다.
  • 스프링에서는 의존 관계를 스프링 자체에서 관리 해주는 데 이러한 특징을 IoC라고 부릅니다.
  • 소스 코드 자체에 객체를 생성시켜주지 않고 Bean을 이용하여 의존 객체를 넣어줌으로써 클래스들간 의존관계를 낮춥니다.

 

 

읽어주셔서 감사합니다.

질문은 언제나 환영합니다.

 

"난 반드시 백엔드 왕이 될거야"

댓글
댓글쓰기 폼
공지사항
Total
248,427
Today
802
Yesterday
1,065
링크
«   2022/10   »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
글 보관함