Back-End/Spring

[Spring] 스프링의 개요 / DI(의존성 주입) 하는 방법 2가지

찐코딩 2021. 12. 10. 14:20

* 스프링 개요
- 선수학습 : java, jsp(servlet), 스크립트언어(html. javascript, css, jquery)
- 개념 : 자바 언어를 기반으로 한 애플리케이션을 제작할 때 효율적으로 빠르게 개발할 수 있도록 하는 애플리케이션 프레임워크(프로그래밍 툴).
                   
* 스프링 프레임워크란?
- 스프링은 엔터프라이즈(기업용) 애플리케이션에서 필요로 하는 여러가지 기능들을 제공하는 프레임워크.
  
- Java EE가 제공하는 기능들을 스프링에서도 지원하고 있기 때문에 국내에서 가장 인기 있는 프레임워크로 자리를 잡았음.
        
- 스프링은 Java EE에서 제공하는 기능 외에 DI나 AOP와 같은 기능들을 추가적으로 제공함.
  
- Java EE에서 MVC-2 모델 방식도 새로운 애플리케이션을 개발할 때마다 일일히 처음부터 다시 개발해야 하는 단점이 있음. 모든 애플리케이션에서 공통적인 기능들을 처음부터 다시 개발해야 한다는 것은 상당히 비효율적임.
이러한 비효율성을 해결하기 위해 고안한 것이 스프링


애플리케이션 개발 시에 일반적인 웹 애플리케이션에서 많이 사용하는 기능들은 미리 만들어서 제공을 하고, 그 외의 필요한 부분만 추가 및 수정하는 방식을 이용하면 됨. 이렇게 하면 훨씬 효율적일 뿐만 아니라 일정한 형식에 따라서 개발을 진행하므로 표준화가 이루어져 생산성도 높일 수 있음.
        
  - 애플리케이션은 규모가 커질수록 각각의 기능들을 개발자가 따로 개발하는 것보다는 표준화된 방법으로 개발하는 것이 상당히 유리함.
        
  - 그렇다면 프레임워크(framework)란?
프레임워크(framework)의 사전적 의미는 "어떤 것을 구성하는 구조 또는 뼈대" 임.
소프트웨어적 의미로는 "기능을 미리 클래스나 인터페이스 등으로 만들어 제공하는 반제품" 정도로 해석을 할 수 있음.

즉, 어느 정도는 완성된 상태로 제공되는 기능을 말함.
        
* 스프링 프레임워크의 특징.
  - 스프링은 경량의 프레임워크.
    * 자바의 객체를 담고 있는 컨테이너(IoC 컨테이너).
    * 객체의 생성, 관리, 소멸과 같은 생명 주기를 관리함.
  - 스프링은 유지보수가 용이함.
  - 스프링은 개발 기간을 효율적으로 단축할 수 있음.

* DI(Dependency Injection : 의존성 주입)
  - DI는 스프링 핵심 개념 중 하나임.
  
  - 기존에는 어떤 한 클래스가 다른 클래스의 기능(메서드)을 사용하려면 당연히 개발자가 코드에서 직접적으로 사용할 클래스의 생성자를 호출해서 사용을 하였음(new 키워드를 이용).
따라서 사용할 클래스와 사용될 클래스의 관계는 개발자에 의해 직접 코드에서 부여가 되었음 (의존도가 높음 - 강한 결합)
    
  - 스프링에서는 객체 사이의 의존 관계를 객체 자신이 아닌 외부(스프링 컨테이너)에서 수행하는 개념임.
        즉, 이런 연관 관계를 개발자가 직접 코딩을 통해서 부여하는 것이 아니라 스프링 컨테이너가 연관 관계를 직접 규정하는 것을 말함. 그러면 코드에서 직접적인 연관 관계가 발생하지 않으므로 각각의 클래스들의 변경이 자유로워짐(약한 결합).
        따라서 스프링 프레임워크에서는 각 클래스들의 연관 관계를 클래스들 간의 사이에서 맺어지는 것이 아니라
        스프링 프레임워크에서 설정을 통해 맺어줌으로써 클래스들끼리 연관 관계를 맺지 않도록 구현을 해 놓았음.
        
  - 스프링 프레임워크에서 의존 관계 설정은 설정 파일(bean.xml)이나 애노테이션을 이용하여 설정을 함.
  
  - 스프링에서 클래스(빈 : bean)를 담는 그릇을 컨테이너라고 함.
        스프링 기반 애플리케이션에서는 스프링 컨테이너에서 객체가 태어나고, 자라고 소멸을 함.
        스프링 컨테이너는 객체를 생성하고, 서로 엮어 주고, 이들의 전체 생명 주기를 관리함.
        스프링 컨테이너는 스프링 프레임워크 핵심부에 위치함. 스프링 컨테이너는 종속 객체 주입을 이용해서
        애플리케이션을 구성하는 컴포넌트를 관리하며, 협력 컴포넌트 간 연관 관계의 형성도 스프링 컨테이너에서
        이루어짐.

* DI(의존성 주입) 하는 방법 - 2가지
  - setter(설정 메서드)를 이용한 주입

  - constructor(인자 생성자)를 이용한 주입


* 의존 관계를 설정하는 방법
  - XML 파일을 이용하여 의존 관계 설정.
  - Java 코드를 이용하여 의존 관계 설정. - 애노테이션을 이용.
  - XML 과 Java 를 혼용해서 의존 관계 설정.

 


예제) DI(의존성 주입) 하는 방법

1. setter(설정 메서드)를 이용한 주입

 

main/resources 탭에 들어가서 new>Spring Bean Configuration File 클릭

getSum.xml 파일을 생성한다.

 

getSum.xml

<?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">
	
	<!-- GetSum getSum = new GetSum(); -->
	<bean id="getSum" class="com.sist.di01.GetSum"/>
	
	
	<bean id="mySum" class="com.sist.di01.MyGetSum">
	<!-- MyGetSum에는 멤버변수가 있고, 생성자가 없으므로 setter()메서드를 통해 주입시켜야 함-->
		<!-- ctrl+space 누르면 멤버변수 나옴 -->
		<property name="su1" value="100"/>
		<property name="su2" value="200"/>
		<property name="getSum">
		<!-- GetSum이라는 클래스를 참조하고 있으므로 -->
			<ref bean="getSum"/>
		</property>
	</bean>
</beans>
<bean id="getSum" class="com.sist.di01.GetSum"/>

위 코드는 자바에서 아래 코드와 같은 의미

GetSum getSum = new GetSum();

 

위에서 참조하는(7행) id를 refernces값으로 가져오면 된다.

 

Main.java

package com.sist.di01;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {

	public static void main(String[] args) {
		
		// AbstractApplicationContext 객체가 DI 작업을 해주는 스프링 컨테이너
		// xml 파일을 이용하여 메모리로 해당 xml 파일이 로딩이 됨
		AbstractApplicationContext ctx =
				new GenericXmlApplicationContext("classpath:getsum.xml");
		
		// getBean은  object 타입으로 반환하므로 형변환을 시켜준다
		MyGetSum mysum = (MyGetSum)ctx.getBean("mySum");
		
		mysum.sum();
		
		// 사용을 한 자원은 반납을 해야 함
		// 컨테이너에 계속적으로 남아있으면 메모리 낭비가 심하므로 반납을 해야 함
		ctx.close();		
	}
}

여기서 MyGetSum mysum = (MyGetSum)ctx.getBean("mySum");는

위 getSum.xml의

<bean id="mySum" class="com.sist.di01.MyGetSum">
	<!-- MyGetSum에는 멤버변수가 있고, 생성자가 없으므로 setter()메서드를 통해 주입시켜야 함-->
		<!-- ctrl+space 누르면 멤버변수 나옴 -->
		<property name="su1" value="100"/>
		<property name="su2" value="200"/>
		<property name="getSum">
		<!-- GetSum이라는 클래스를 참조하고 있으므로 -->
			<ref bean="getSum"/>
		</property>
	</bean>

을 호출한다.

 

2. constructor(인자 생성자)를 이용한 주입

 

Exam.java

package com.sist.di04;

public class Exam {
	
	private String msg;
	
	// 기본 생성자
	public Exam() {
		// TODO Auto-generated constructor stub
	}
	
	// 인자생성자
	public Exam(String msg) {
		this.msg=msg;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}
	
	// 비즈니스 로직
	public void output() {
		System.out.println("메세지 : "+msg);		
	}

}

Spring Bean Configuration File 생성

exam.xml

<?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="exam" class="com.sist.di04.Exam">
	<!-- DI(의존성 주입)하는 2번째 방법: constructor(인자 생성자)를 이용한 주입 -->
	<!-- 여기서 생성된 값을  com.sist.di04.Exam의 매개변수로 넘긴다. -->
		<constructor-arg value="안녕하세요, 스프링에 오신 걸 환영합니다."/>
	</bean>
</beans>

Main.java

package com.sist.di04;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {

	public static void main(String[] args) {
		
		
		AbstractApplicationContext ctx =
				new GenericXmlApplicationContext("classpath:exam.xml");
		
		// 아래 코드는 Exam exam = (Exam)ctx.getBean("exam"); 와 같음
		Exam exam = ctx.getBean("exam", Exam.class);
		
		exam.output();
		
		ctx.close();

	}

}

결과

INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [exam.xml]
INFO : org.springframework.context.support.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@2957fcb0: startup date [Mon Dec 13 09:36:36 KST 2021]; root of context hierarchy
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2d3fcdbd: defining beans [exam]; root of factory hierarchy
메세지 : 안녕하세요, 스프링에 오신 걸 환영합니다.
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@2957fcb0: startup date [Mon Dec 13 09:36:36 KST 2021]; root of context hierarchy
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2d3fcdbd: defining beans [exam]; root of factory hierarchy