Study Web Development

2월 23일

이전으로

Spring

1. 스프링 기초

1-1 스프링 프레임워크란?

소프트웨어 프레임워크

1-2 스프링 프레임워크 특징

1-3 스프링 프레임워크 설치

  1. Open Perspective-Spring 선택
  2. Package Explorer에서 New-Spring Legacy Project 선택하고, 프로젝트명에 ch01DI 입력 후 Spring MVC Project를 선택 후 Next
  3. 프로젝트 최상위 패키지명을 kr.spring.di로 입력 후 Finish
  4. src/main/resources에 설정 파일을 보관하며, src/main/webapp/resources는 CSS나 이미지 등을 보관
  5. pom.xml 열고 편집 가능하도록 하단에서 pom.xml 탭을 선택하여 <properties> 태그 사이의 내용을 다음처럼 수정
		<java-version>1.8</java-version>
		<org.springframework-version>5.0.20.RELEASE</org.springframework-version>
  1. 프로젝트의 Properties에서 Java Build Path의 JRE System Library와 Project Facets의 Java 버전을 1.8로 변경
  2. kr.spring.di 패키지 삭제
Maven

https://mvnrepository.com/

2. 스프링 DI와 객체 관리

2-1 DI란

2-2 Bean 객체 설정 및 컨테이너를 통한 Bean 객체 사용

  1. src/main/java를 오른쪽 클릭하고 새 패키지 kr.spring.ch01 생성 후 새 클래스 MessageBean 생성
package kr.spring.ch01;

public class MessageBean {
	public void sayHello(String name) {
		System.out.println("Hello, " + name);
	}
}
  1. src/main/resources를 오른쪽 클릭하고 New-Spring Bean Configuration File 선택 후 이름에 applicationContext.xml 입력하고 Next
  2. XSD namespace에서 aop, beans, context를 선택하고 각각 가장 위에 있는 XSD를 선택, XSD namespace에서 p를 추가로 선택하여 Next-Finish
  3. applicationContext.xml 파일이 열리면 하단의 Source 탭 선택하고 <beans> 태그 내에 다음의 내용을 추가
	<!-- 객체 생성을 위한 설정(Spring Container) -->
	<!-- 
	name : 컨테이너에 보관되는 bean 객체를 식별할 때 사용할 이름; 생성자를 이용하여 객체 주소를 직접 얻을 수 없기 때문에 식별자가 필요하며, 식별자는 유일해야 함
	class : bean 객체를 생성할 때 사용할 클래스명
	 -->
	<bean name="messageBean" class="kr.spring.ch01.MessageBean"/>
  1. 새 클래스 SpringMain 생성
package kr.spring.ch01;

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

public class SpringMain {
	public static void main(String[] args) {
		// applicationContext.xml 설정 파일을 읽어들여 Spring Container 생성
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		// 식별자를 이용해 객체를 컨테이너로부터 읽어옴
		MessageBean messageBean = (MessageBean)context.getBean("messageBean");
		messageBean.sayHello("초코");
		
		// 어플리케이션 종료시 컨테이너에 존재하는 모든 bean을 종료
		context.close();
	}
}
  1. 새 패키지 kr.spring.ch02 생성하고 새 클래스 StudentBean 생성
package kr.spring.ch02;

public class StudentBean {
	public void study(String course) {
		System.out.println(course + "을 공부합니다.");
	}
}
  1. applicationContext.xml<beans> 태그 사이에 다음의 내용을 추가
	<bean name="studentBean" class="kr.spring.ch02.StudentBean"/>
  1. kr.spring.ch02 패키지에 새 클래스 SpringMain 생성
package kr.spring.ch02;

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

public class SpringMain {
	public static void main(String[] args) {
		// applicationContext.xml 설정 파일을 읽어들여 Spring Container를 생성
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		// 객체를 컨테이너로부터 읽어옴
		StudentBean studentBean = (StudentBean)context.getBean("studentBean");
		studentBean.study("개발");
		
		// 어플리케이션 종료시 컨테이너에 존재하는 모든 bean을 종료
		context.close();
	}
}
  1. 새 패키지 kr.spring.ch03 생성하고 새 클래스 OperatorBean 생성
package kr.spring.ch03;

public class OperatorBean {
	public int add(int a, int b) {
		return a + b;
	}
}
  1. applicationContext.xml<beans> 태그 사이에 다음의 내용을 추가
	<bean name="operatorBean" class="kr.spring.ch03.OperatorBean"/>
  1. kr.spring.c03 패키지에 새 클래스 SpringMain 생성
package kr.spring.ch03;

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

public class SpringMain {
	public static void main(String[] args) {
		// applicationContext.xml 설정 파일을 읽어들여 Spring Container를 생성
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		// 객체를 컨테이너로부터 읽어옴
		OperatorBean bean = (OperatorBean)context.getBean("operatorBean");
		int result = bean.add(10, 20);
		
		System.out.println("결과 : " + result);
		
		// 어플리케이션 종료시 컨테이너에 존재하는 모든 bean을 종료
		context.close();
	}
}

2-3 의존 관계 설정

2-3-1 생성자 방식
  1. 새 패키지 kr.spring.ch04 생성하고 새 클래스 WriteArticleDAO 생성
package kr.spring.ch04;

public class WriteArticleDAO {
	public void insert() {
		System.out.println("WriteArticleDAO의 insert() 메서드 실행");
	}
}
  1. 새 클래스 WriteArticleService 생성
package kr.spring.ch04;

public class WriteArticleService {
	private WriteArticleDAO writeArticleDAO;
	
	public WriteArticleService(WriteArticleDAO writeArticleDAO) {
		this.writeArticleDAO = writeArticleDAO;
	}
	
	public void write() {
		System.out.println("WriteArticleService의 write() 메서드 실행");
		
		writeArticleDAO.insert();
	}
}
  1. applicationContext.xml<beans> 태그 사이에 다음의 내용을 추가
	<!-- 의존 관계 주입 : 생성자 방식 -->
	<bean name="writeArticleService" class="kr.spring.ch04.WriteArticleService">
		<constructor-arg>
			<!-- ref : 주입할 의존 객체에 해당하는 bean 객체의 식별값 -->
			<ref bean="writeArticleDAO"/>
		</constructor-arg>	
	</bean>
	<bean name="writeArticleDAO" class="kr.spring.ch04.WriteArticleDAO"/>
  1. kr.spring.ch04 패키지에 새 클래스 SpringMain 생성
package kr.spring.ch04;

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

public class SpringMain {
	public static void main(String[] args) {
		// applicationContext.xml 설정 파일을 읽어들여 스프링 컨테이너를 생성
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		// 컨테이너에 DI 생성자 설정 방식으로 생성된 객체를 읽어옴
		WriteArticleService articleService = (WriteArticleService)context.getBean("writeArticleService");
		articleService.write();
		
		// 어플리케이션 종료시 컨테이너에 존재하는 모든 bean을 종료
		context.close();
	}
}
  1. kr.spring.ch05 생성 후 새 클래스 MemberDAO 생성
package kr.spring.ch05;

public class MemberDAO {
	public void register() {
		System.out.println("MemberDAO의 register() 메서드 실행");
	}
}
  1. 새 클래스 MemberService 생성
package kr.spring.ch05;

public class MemberService {
	private MemberDAO memberDAO;
	
	public MemberService(MemberDAO memberDAO) {
		this.memberDAO = memberDAO;
	}
	
	public void send() {
		System.out.println("MemberService의 send() 메서드 실행");
		memberDAO.register();
	}
}
  1. applicationContext.xml<beans> 태그 사이에 다음의 내용을 추가
	<!-- 의존 관계 주입 : 생성자 방식 -->
	<bean name="memberService" class="kr.spring.ch05.MemberService">
		<constructor-arg>
			<!-- ref : 주입할 의존 객체에 해당하는 bean 객체의 식별값 -->
			<ref bean="memberDAO"/>
		</constructor-arg>
	</bean>
	<bean name="memberDAO" class="kr.spring.ch05.MemberDAO"/>
  1. kr.spring.ch05 패키지에 새 클래스 SpringMain 생성
package kr.spring.ch05;

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

public class SpringMain {
	public static void main(String[] args) {
		// applicationContext.xml 설정 파일을 읽어 들여 Spring Container를 생성
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		// 컨테이너에 DI 생성자 설정 방식으로 생성된 객체를 읽어옴
		MemberService memberService =  (MemberService)context.getBean("memberService");
		memberService.send();
		
		// 어플리케이션이 종료시 컨테이너에 존재하는 모든 bean을 종료
		context.close();
	}
}
  1. 새 패키지 kr.spring.ch06 생성 후 새 클래스 SmsSender 생성하고 오른쪽 클릭하여 Source-Generate toString()... 선택
package kr.spring.ch06;

public class SmsSender {
	@Override
	public String toString() {
		return "SmsSender 호출";
	}
}
  1. 새 클래스 SystemMonitor 생성하고 멤버 변수 선언 후 오른쪽 클릭한 다음 Source-Generate Constructor using Fields... 선택
package kr.spring.ch06;

public class SystemMonitor {
	private long periodTime;
	private SmsSender sender;
	
	public SystemMonitor(long periodTime, SmsSender sender) { // super()는 생략해도 암묵적으로 포함됨
		this.periodTime = periodTime;
		this.sender = sender;
	}

	@Override
	public String toString() {
		return "SystemMonitor [periodTime=" + periodTime + ", sender=" + sender + "]";
	}
}
  1. applicationContext.xml<beans> 태그 사이에 다음의 내용을 추가
	<!-- DI 생성자 설정 방식 : 여러 개의 인자 사용 -->
	<bean name="monitor" class="kr.spring.ch06.SystemMonitor">
		<!-- (주의) 인자의 순서대로 기재 -->
		<!-- 
		<constructor-arg>
			<value>10</value>
		</constructor-arg>
		<constructor-arg>
			<ref bean="smsSender"/>
		</constructor-arg>
		 -->
		
		<!-- 속성으로 값 또는 객체 설정 -->
		<!-- 
		<constructor-arg value="20"/>
		<constructor-arg ref="smsSender"/>
		 -->
		
		<!-- 순서를 무시할 때는 index를 함께 명시 -->
		<!-- 
		<constructor-arg index="1" ref="smsSender"/>
		<constructor-arg index="0" value="30"/>
		 -->
		
		<!-- 생성자의 인자명 기재 -->
		<constructor-arg name="periodTime" value="40"/>
		<constructor-arg name="sender" ref="smsSender"/>
	</bean>
	<bean name="smsSender" class="kr.spring.ch06.SmsSender"/>
  1. 새 클래스 SpringMain 호출
package kr.spring.ch06;

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

public class SpringMain {
	public static void main(String[] args) {
		// applicationContext.xml 설정 파일을 읽어들여 Spring Container를 생성
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		// DI 생성자 설정 방식
		SystemMonitor monitor = (SystemMonitor)context.getBean("monitor");
		System.out.println(monitor);
		
		context.close();
	}
}
2-3-2 프로퍼티 설정 방식
  1. 새 패키지 kr.spring.ch07 생성 후 새 클래스 RegisterDAO 생성
package kr.spring.ch07;

public class RegisterDAO {
	public void insert() {
		System.out.println("RegisterDAO의 insert() 메서드 실행");
	}
}
  1. 새 클래스 RegisterService 생성
package kr.spring.ch07;

public class registerService {
	private RegisterDAO registerDAO;
	
	// 의존 관계 설정 방식 : 프로퍼티
	public void setRegisterDAO(RegisterDAO registerDAO) { // 생성자는 기본 생성자를 사용하고, setter 메서드를 통해 객체의 주소를 전달; 표준적인 setter 메서드 명명 방식을 준수하지 않으면 에러
		this.registerDAO = registerDAO; 
	}
	
	public void write() {
		System.out.println("RegisterService의 write() 메서드 실행");
		registerDAO.insert();
	}
}
  1. applicationContext.xml을 복사 붙여넣기하여 applicationContext2.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"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DI 프로퍼티 설정 방식 -->
	<!-- bean 태그의 식별자는 name으로 부여해도 되고 id로 부여해도 됨 -->
	<bean id="registerService" class="kr.spring.ch07.RegisterService">
		<property name="registerDAO">
			<!-- ref : 주입할 의존 객체에 해당하는 bean 객체의 식별값 -->
			<ref bean="registerDAO"/>
		</property>
	</bean>
	<bean id="registerDAO" class="kr.spring.ch07.RegisterDAO"/>
</beans>
  1. kr.spring.ch07 패키지에 새 클래스 SpringMain 생성
package kr.spring.ch07;

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

public class SpringMain {
	public static void main(String[] args) {
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
		
		// DI 프로퍼티 설정 방식
		RegisterService service = (RegisterService)context.getBean("registerService");
		service.write();
		
		context.close();
	}
}
  1. 새 패키지 kr.spring.ch08에 새 클래스 EmailSender 생성
package kr.spring.ch08;

public class EmailSender {
	@Override
	public String toString() {
		return "EmailSender 호출";
	}	
}
  1. 새 패키지 WorkController 생성
package kr.spring.ch08;

public class WorkController {
	private long periodTime;
	private EmailSender email;
	
	public void setPeriodTime(long periodTime) {
		this.periodTime = periodTime;
	}
	public void setEmail(EmailSender email) {
		this.email = email;
	}
	
	@Override
	public String toString() {
		return "WorkController [periodTime=" + periodTime + ", email=" + email + "]";
	}
}
  1. applicationContext2.xml<beans> 태그 사이에 다음의 내용을 추가
	<!-- DI 프로퍼티 설정 방식 : 여러 개의 프로퍼티 -->
	<bean id="work" class="kr.spring.ch08.WorkController">
		<!-- property 태그의 경우 항상 프로퍼티명을 명시하므로 순서 무관 -->
		<property name="periodTime">
			<value>10</value>
		</property>
		<property name="email"> <!-- WorkController의 프로퍼티명 -->
			<ref bean="email"/> <!-- bean 식별자 -->
		</property>
	</bean>
	<bean id="email" class="kr.spring.ch08.EmailSender"/>
  1. kr.spring.ch08 패키지에 새 클래스 SpringMain 생성
package kr.spring.ch08;

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

public class SpringMain {
	public static void main(String[] args) {
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
		
		// DI 프로퍼티 설정 방식 : 여러 개의 프로퍼티 사용
		WorkController work = (WorkController)context.getBean("work");
		System.out.println(work);
		
		context.close();
	}
}
2-3-3 XML 네임스페이스를 이용한 프로퍼티 설정
  1. 새 패키지 kr.spring.ch09 생성하고 새 클래스 ImageSender 생성
package kr.spring.ch09;

public class ImageSender {
	@Override
	public String toString() {
		return "ImageSender 호출";
	}
}
  1. 새 클래스 UploadController 생성
package kr.spring.ch09;

public class UploadController {
	private long timeout;
	private ImageSender image;
	
	public void setTimeout(long timeout) {
		this.timeout = timeout;
	}
	public void setImage(ImageSender image) {
		this.image = image;
	}
	
	@Override
	public String toString() {
		return "UploadController [timeout=" + timeout + ", image=" + image + "]";
	}
}
  1. applicationContext2.xml<beans> 태그 사이에 다음의 내용을 추가
	<!-- XML 네임스페이스를 이용한 프로퍼티 설정 -->
	<bean id="upload" class="kr.spring.ch09.UploadController" p:timeout="50" p:image-ref="image"/>
	<bean id="image" class="kr.spring.ch09.ImageSender"/>
  1. kr.spring.ch09 패키지에 새 클래스 SpringMain 생성
package kr.spring.ch09;

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

public class SpringMain {
	public static void main(String[] args) {
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
		
		// XML 네임스페이스를 이용한 프로퍼티 설정
		UploadController upload = (UploadController)context.getBean("upload");
		System.out.println(upload);
		
		context.close();		
	}
}
2-3-6 콜렉션 타입 프로퍼티 설정
List 타입과 배열
  1. kr.spring.ch10 패키지에 새 클래스 PerformanceMonitor 생성
package kr.spring.ch10;

import java.util.List;

public class PerformanceMonitor {
	private List<Double> deviations;

	public void setDeviations(List<Double> deviations) {
		this.deviations = deviations;
	}

	@Override
	public String toString() {
		return "PerformanceMonitor [deviations=" + deviations + "]";
	}
}
  1. applicationContext2.xml<beans> 태그 사이에 다음의 내용을 추가
	<!-- List 타입 프로퍼티 설정 -->
	<bean id="performanceMonitor" class="kr.spring.ch10.PerformanceMonitor">
		<property name="deviations">
			<list> <!-- 컨테이너가 List 타입 객체를 생성하여 deviations에 전달 -->
				<value>0.2</value>
				<value>0.3</value>
				<!-- 문자열일 경우 <value>String</value> -->
				<!-- 객체일 경우 <ref bean="SomeDemo"/> -->
			</list>
		</property>
	</bean>
  1. kr.spring.ch10 패키지에 새 클래스 SpringMain 생성
package kr.spring.ch10;

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

public class SpringMain {
	public static void main(String[] args) {
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
		
		// List 타입 프로퍼티 설정
		PerformanceMonitor monitor = (PerformanceMonitor)context.getBean("performanceMonitor");
		System.out.println(monitor);
		
		context.close();
	}
}
Map 타입
  1. 새 패키지 kr.spring.ch11 생성 후 새 클래스 RestHandler, SoapHandler, ProtocolHandlerFactory 생성
package kr.spring.ch11;

import java.util.Map;

public class ProtocolHandlerFactory {
	private Map<String, Object> map;

	public void setMap(Map<String, Object> map) {
		this.map = map;
	}

	@Override
	public String toString() {
		return "ProtocolHandlerFactory [map=" + map + "]";
	}
}
  1. applicationContext2.xml<beans> 태그 사이에 다음의 내용을 추가
	<!-- Map 타입 프로퍼티 설정 -->
	<bean id="protocolHandlerFactory" class="kr.spring.ch11.ProtocolHandlerFactory">
		<property name="map">
			<map>
				<entry>
					<key><value>soap</value></key> <!-- 프로퍼티 map은 key 자료형이 String이므로 <value>로 key에 넣을 문자열 전달 -->
					<ref bean="soapHandler"/> <!-- 프로퍼티 map은 value 자료형이 Object이므로 <ref bean>으로 value에 넣을 객체 전달 -->
				</entry>
				<entry>
					<key><value>rest</value></key>
					<ref bean="restHandler"/>
				</entry>
			</map>
		</property>
	</bean>
	<bean id="soapHandler" class="kr.spring.ch11.SoapHandler"/>
	<bean id="restHandler" class="kr.spring.ch11.RestHandler"/>
  1. kr.spring.ch11 패키지에 새 클래스 SpringMain 생성
package kr.spring.ch11;

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

public class SpringMain {
	public static void main(String[] args) {
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
		
		// Map 타입 프로퍼티 설정
		ProtocolHandlerFactory protocol = (ProtocolHandlerFactory)context.getBean("protocolHandlerFactory");
		System.out.println(protocol);
		
		context.close();
	}
}
Set 타입
  1. 새 패키지 kr.spring.ch12 생성하고 새 클래스 VideoClient 생성
package kr.spring.ch12;

import java.util.Set;

public class VideoClient {
	private Set<Integer> subSet;

	public void setSubSet(Set<Integer> subSet) {
		this.subSet = subSet;
	}

	@Override
	public String toString() {
		return "VideoClient [subSet=" + subSet + "]";
	}
}
  1. applicationContext2.xml<beans> 태그 사이에 다음의 내용을 추가
	<!-- Set 타입 프로퍼티 설정 -->
	<bean id="videoClient" class="kr.spring.ch12.VideoClient">
		<property name="subSet">
			<set> <!-- 컨테이너에서 Set 타입 객체를 생성하여 subSet에 전달 -->
				<value>10</value>
				<value>20</value>
			</set>
		</property>
	</bean>
  1. kr.spring.ch12 패키지에 새 클래스 SpringMain 생성
package kr.spring.ch12;

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

public class SpringMain {
	public static void main(String[] args) {
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
		
		// Set 타입 프로퍼티 설정
		VideoClient video = (VideoClient)context.getBean("videoClient");
		System.out.println(video);
		
		context.close();		
	}
}

다음으로