본문 바로가기

학원/복기

[Spring] 의존성 주입(Dependency Injection)

Dependency 관리

 

Dependency 관리는 Spring에서 Famework가 관리하는 Bean을 다른 Bean에서 사용할 수 있도록 설정해주는 역할까지 대행하는 것을 말한다.

 

 

 

예제)

 

xyz.itwill05.di 패키지 생성

 

학생정보를 저장하기 위한 클래스, 즉 VO 클래스(DTO 클래스, POJO 클래스 -  Plane Old Java Object) [Student]를 선언

→ 학생정보를 표현하기 위한 값을 필드에 저장할 것이다.

 

* POJO란 특정 기술에 종속되지 않는 순수한 자바 객체를 말한다.

 

package xyz.itwill05.di;

//학생 정보를 저장하기 위한 VO클래스(DTO 클래스)
public class Student {
	private int num;
	private String name;
	private String email;
	
	public Student() {
		System.out.println("### Student 클래스의 기본 생성자 호출 ###");
	}

	public Student(int num) {
		super();
		this.num = num;
		System.out.println("### Student 클래스의 매개변수(학번)가 선언된 생성자 호출 ###");
	}

	public Student(int num, String name) {
		super();
		this.num = num;
		this.name = name;
		System.out.println("### Student 클래스의 매개변수(학번, 이름)가 선언된 생성자 호출 ###");
	}

	public Student(int num, String name, String email) {
		super();
		this.num = num;
		this.name = name;
		this.email = email;
		System.out.println("### Student 클래스의 매개변수(학번, 이름, 이메일)가 선언된 생성자 호출 ###");
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
		System.out.println("*** Student 클래스의 setNum(int num) 메소드 호출 ***");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
		System.out.println("*** Student 클래스의 setName(String name) 메소드 호출 ***");
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
		System.out.println("*** Student 클래스의 setEmail(String email) 메소드 호출 ***");
	}
	
	//Object 클래스에 있는 메소드
	//toString() 메소드가 빠지면 DTO 클래스이다 
	@Override
	public String toString() {
		return "학번 = "+num+", 이름 = "+name+", 이메일 = "+email;
	}
}

 

스프링 컨테이너는 클래스의 기본 생성자를 사용하여 객체를 생성하기 때문에 객체 필드에는 기본값이 들어간다.

(기본값은 숫자형 : 0, 논리형 : false, 참조형 : null 값이다.)

 

[05-1_di.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 class="xyz.itwill05.di.Student" id="student1"/>
</beans>

 

 

main  메소드 선언할 [StudentApp] 클래스 선언 

package xyz.itwill05.di;

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

public class StudentApp {
	public static void main(String[] args) {
		System.out.println("================ Spring Container 초기화 전 ================");
		ApplicationContext context=new ClassPathXmlApplicationContext("05-1_di.xml");
		System.out.println("================ Spring Container 초기화 후 ================");
		Student student1=context.getBean("student1", Student.class);
		//참조변수를 출력할 경우 toString() 메소드를 자동으로 호출 - 객체의 초기값 확인
		System.out.println(student1);
		System.out.println("============================================================");
		((ClassPathXmlApplicationContext)context).close();
	}
}

객체 필드에 기본값이 들어간 것을 확인할 수 있다.

 


객체를 만들 때 객체 필드에 원하는 값을 넣고 싶은 경우 어떻게 해야할까?

 

Spring을 이용해 Spring Injection이라는 기술을 이용할 수 있다.

 

의존성 주입(Dependency Injection)

 

Dependency Injection은 스프링 컨테이너에 의해 Spring Bean Configuration File에 등록된 클래스를 객체로 생성할 때 객체 필드에 필요한 값(객체)를 저장되도록 설정하는 기능이다.

 

Constructor, Setter, Field 세가지 방법이 존재하는데 그 중에서 생성자(Constructor Injection) 또는 Setter 메소드(Setter Injection)를 사용하여 객체 필드에 값(객체)를 저장하는 방법에 대해 알아보자.

 


1. Constructor Injection

Constructor Injection은 스프링 컨테이너가 클래스의 매개변수가 선언된 생성자를 사용해 객체를 생성하는 방법이다.

→ 생성자의 매개변수에 전달된 값(객체)을 이용하여 필드값으로 저장한다.

 

Constructor Injection은 생성자를 사용하여 객체 필드에 값(객체)를 저장하는 방법이다.

이 방법을 사용하기 위해선 bean 엘리먼트의 하위 엘리먼트로 constructor-arg 엘리먼트를 사용해야 한다.

 

constructor-arg : 생성자 매개변수에 값(객체)를 전달하는 엘리먼트 - 생성자 매개변수에 값이나 객체를 전달해 초기화 시킬 수 있도록 한다.

→ constructor-arg 엘리먼트의 갯수만큼 매개변수가 선언된 생성자를 반드시 작성해주어야 한다. (작성하지 않으면 객체가 생성되지 않는다.)

  • value 속성 : 생성자 매개변수에 전달되어 저장될 값을 속성값으로 설정한다.
  • → 필드에 값이 저장되도록 설정하는 속성이다. 이를 '값 주입(Value Injection)' 이라고 부른다.
  • → 매개변수에 전달되는 값은 기본적으로 문자열로 취급하지만 매개변수의 자료형에 의해 자동 형변환 된다.
  • → 매개변수의 자료형에 의해 자동 형변환시 NumberFormatException이 발생될 수 있기 때문에 주의해야 한다. ex) 전달값이 문자형인데 매개변수의 자료형이 int 일 경우 

[05_di.xml]

<bean class="xyz.itwill05.di.Student" id="student2">
	<constructor-arg value="1000"/><!-- 문자열로 전달되지만 매개변수의 자료형에 의해 자동 형변환된다 -->
</bean>

 

[StudentApp]

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

public class StudentApp {
	public static void main(String[] args) {
    		...
        
		ApplicationContext context=new ClassPathXmlApplicationContext("05-1_di.xml");
        
       	 	...
        
		Student student2=context.getBean("student2", Student.class);
		System.out.println(student2);
        
       		...
		((ClassPathXmlApplicationContext)context).close();
	}
}

 

 

만약 매개변수가 하나인 생성자를 두개 선언한 경우에 다시 실행하게 되면, num을 매개변수로 갖고있는 생성자는 사용되지 않는다. (전달값이 "1000" 이기 때문에 자료형이 String인 매개변수의 생성자에 값이 대입된다)

public Student(int num) {
	super();
	this.num = num;
	System.out.println("### Student 클래스의 매개변수(학번)가 선언된 생성자 호출 ###");
}
	
public Student(String name) {
	super();
	this.name = name;
	System.out.println("### Student 클래스의 매개변수(이름)가 선언된 생성자 호출 ###");
}

 

 

 

따라서 매개변수의 갯수를 다르게 쓰는 것을 권장한다.

 

 

 

indext 속성 

 

contructor-arg 엘리먼트의 작성순서에 의해 매개변수에 값(객체)이 차례대로 전달되어 저장된다.

<!-- 매개변수가 3개인 생성자 사용 -->
<bean class="xyz.itwill05.di.Student" id="student3">
	<constructor-arg value="1000"/>
	<constructor-arg value="홍길동"/>
	<constructor-arg value="abc@itwill.xyz"/>
</bean>

 

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

public class StudentApp {
	public static void main(String[] args) {
    		...
        
		ApplicationContext context=new ClassPathXmlApplicationContext("05-1_di.xml");
        
       	 	...
        
		Student student3=context.getBean("student3", Student.class);
		System.out.println(student3);

        
       		...
		((ClassPathXmlApplicationContext)context).close();
	}
}

 

 

 

 

index 속성을 이용해 전달 순서를  지정할 수 있다.

 

index 속성 : 생성자 매개변수에 값(객체)를 전달하기 위한 순서를 속성값으로 설정할 수 있다.

→ index 속성값은 0부터 1씩 증가되는 정수값을 사용하면 된다.

<bean class="xyz.itwill05.di.Student" id="student3">
	<constructor-arg value="1000" index="2"/>
	<constructor-arg value="abc@itwill.xyz" index="0"/>
	<constructor-arg value="홍길동" index="1"/>
</bean>

 


2) Setter Injection 

 

스프링 컨테이너는 클래스의 기본 생성자를 사용하여 객체를 생성하기 때문에 객체 필드에는 기본값이 저장되는데,

객체 생성 후 필드의 Setter 메소드를 호출하여 필드값으로 저장(변경)하는 것이 Setter Injection이다.

 

Setter InjectionSetter 메소드를 사용하여 객체 필드에 값(객체)를 저장하는 방법이다.

Setter Injection은 bean 엘리먼트의 하위 엘리먼트로 property 엘리먼트를 사용하여 설정할 수 있다. 

 

property 

: 객체 필드의 Setter 메소드를 호출하여 필드값을 변경하는 엘리먼트

  • name 속성 : 필드값을 변경할 필드명을 속성값으로 설정한다. - 자동 완성 기능 사용 가능 
  • → name 속성값으로 설정된 필드에 대한 Setter 메소드를 자동으로 호출하여 필드값을 변경한다. 
  • → 필드에 대한 Setter 메소드가 없거나 형식에 맞지 않게 선언된 경우엔 예외가 발생할 수 있다. 
  • value 속성 :  Setter 메소드 매개변수에 전달되어 저장될 값을 속성값으로 설정한다.
  • → 매개변수에 저장된 값을 필드값으로 저장되도록 설정하는 설정 - 값 주입(Value Injection) 
<bean class="xyz.itwill05.di.Student" id="student4">
	<property name="num" value="3000"/>
	<property name="name" value="임꺽정"/>
	<property name="email" value="xyz@itwill.xyz"/>
</bean>

 

Constructor Injection과 Setter Injection을 같이 사용하여 객체 초기화 작업하는 것도 가능하다.

<bean class="xyz.itwill05.di.Student" id="student5">
	<constructor-arg value="4000"/>
	<constructor-arg value="전우치"/>
	<property name="email" value="opq@itwill.xyz"/>
</bean>

 

 


PropertyPlaceholderConfigurer 클래스를 Spring Bean으로 등록해보자

 

[student.properties] 파일 생성

 

name = 일지매 (부호화 처리)

 

PropertyPlaceholderConfigurer 클래스

: Properties 파일을 제공받아 파일에 저장된 값을 Spring Bean Configuratino File에서 사용할 수 있도록 제공하는 클래스

  • locations 필드에 Properties 파일의 경로를 전달하여 저장시키면 된다.
  • Properties 파일에 의해 제공되는 값을 Spring Bean Configuratino File에서는 ${이름} 형식으로 표현하여 사용할 수 있다.

 

	<bean class="org.springframework.context.support.PropertyPlaceholderConfigurer">
		<property name="locations" value="xyz/itwill05/di/student.properties"/>
	</bean>
	
	<bean class="xyz.itwill05.di.Student" id="student6">
		<property name="num" value="${num}"/>
		<property name="name" value="${name}"/>
		<property name="email" value="${email}"/>
	</bean>

 

Student student6=context.getBean("student6", Student.class);
System.out.println(student6);

 

 

 

Spring 5.2 이상에서는 PropertySourcesPlaceholderConfigurer 클래스를 사용해야 한다.

<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
	<property name="locations" value="xyz/itwill05/di/student.properties"/>
</bean>

 


예제)

 

학생정보를 처리하는 DAO 클래스가 상속받아야 하는 인터페이스 [StudentDAO] 를 선언한다. 

인터페이스를 선언하는 이유는 객체간의 결합도를 낮춰 유지보수의 효율성을 증가시키기 위해서이다. 

 

package xyz.itwill05.di;

import java.util.List;

//학생정보를 처리하는 DAO 클래스가 상속받아야 하는 인터페이스
public interface StudentDAO {
	int insertStudent(Student student);
	int updateStudent(Student student);
	int deleteStudent(int num);
	Student selectStudent(int num);
	List<Student> selectStudentList();
}

 

 

DAO 클래스 [StudentJdbcDAO] 선언

 

*DAO 클래스 : 저장매체(File, DBMS 등) 행의 삽입, 변경, 삭제, 검색 기능을 제공하는 클래스

 

저장매체의 종류 또는 방법에 따라 DAO 클래스는 변경될 수 있다. 

 

따라서 DAO 클래스가 변경되더라도 DAO 클래스를 사용하는 클래스(Service 클래스)의 영향을 최소화 하기 위해서는 인터페이스를 반드시 상속받아서 작성해야 한다. 그래야만 결합도를 낮춰 유지보수의 효율성을 증가시킬 수 있기 때문이다. 

 

package xyz.itwill05.di;

import java.util.List;

//DAO 클래스 : 저장매체(File, DBMS 등) 행의 삽입, 변경, 삭제, 검색 기능을 제공하는 클래스
// => 저장매체의 종류 또는 방법에 따라 DAO 클래스는 변경 가능 
public class StudentJdbcDAO  implements StudentDAO {
	public StudentJdbcDAO() {
		System.out.println("### StudentJdbcDAO 클래스의 기본 생성자 호출 ###");
	}
	
	@Override
	public int insertStudent(Student student) {
		System.out.println("*** StudentJdbcDAO 클래스의 insertStudent(Student student) 메소드 호출***");
		return 0;
	}

	@Override
	public int updateStudent(Student student) {
		System.out.println("*** StudentJdbcDAO 클래스의 updateStudent(Student student) 메소드 호출***");
		return 0;
	}

	@Override
	public int deleteStudent(int num) {
		System.out.println("*** StudentJdbcDAO 클래스의 deleteStudent(int num) 메소드 호출***");
		return 0;
	}

	@Override
	public Student selectStudent(int num) {
		System.out.println("*** StudentJdbcDAO 클래스의 selectStudent(int num) 메소드 호출***");
		return null;
	}

	@Override
	public List<Student> selectStudentList() {
		System.out.println("*** StudentJdbcDAO 클래스의  selectStudentList() 메소드 호출***");
		return null;
	}

}

 

실제 필요한 데이터 처리 역할은 Service 클래스가 해준다. 

 

Service 인터페이스 [StudentService]를 먼저 생성해주자 (학생정보를 처리하는 Service 클래스가 반드시 상속받아야 되는 인터페이스)

package xyz.itwill05.di;

import java.util.List;

//학생정보를 처리하는 Service 클래스가 반드시 상속받아야 되는 인터페이스
public interface StudentService {
	void addStudent(Student student);
	void modifyStudent(Student student);
	void removeStudent(int num);
	Student getStudent(int num);
	List<Student> getStudentList();
}

 

Service 클래스인 [StudentServiceImpl] 를 선언한다.

 

*Service 클래스는 프로그램 실행에 필요한 데이터 처리 기능을 제공하는 클래스이며, 컴포넌트라고도 부른다.

  •  Service 클래스의 메소드는 다수의 DAO 객체로 메소드를 호출하여 작성한다.  이를 DAO 모듈화 라고 한다.
  •  Service 클래스의 메소드에서 DAO 객체를 사용하기 위해 포함관계(의존관계)로 설정해야 한다.
  •  Service 클래스가 변경돼도 Service 클래스를 사용하는 클래스(컨트롤러, 즉  모델)에 영향을 최소화 하기 위해 반드시 인터페이스를 상속받아서 작성해야 한다. (결합도를 낮추어 유지보수의 효율성이 증가한다.)

 

 [StudentServiceImpl] Service 클래스에 StudentJdbcDAO 클래스로 필드 선언 - StudentJdbcDAO 객체만 저장이 가능한 필드
→ 필드에 StudentJdbcDAO 객체를 저장해야만 포함관계(의존관계)가 완성된다.
→ StudentServiceImpl 클래스의 메소드에서 필드에 저장된 StudentJdbcDAO 객체로 메소드를 호출할 수 있다.

 

private StudentJdbcDAO studentJdbcDAO;


하지만 DAO 클래스가 변경될 경우 Service 클래스의 필드 및 메소드를 변경할 수 있다는 문제점이 발생할 수 있다.
때문에 결합도가 높아 유지보수가 어려워진다. 

 

때문에 StudentDAO 인터페이스로 필드를 선언해주는 것이 좋다. 

  • 필드에 StudentDAO 인터페이스를 상속받은 DAO 클래스의 객체를 저장해야지만 포함관계(의존관계)가 완성된다.
  • StudentServiceImpl 클래스의 메소드에서 인터페이스로 생성된 필드의 추상메소드를 호출하면 필드에 저장된 자식클래스 객체의 메소드를 호출한다. 이를 오버라이드에 의한 다형성이라고 한다.
  • DAO 클래스가 변경돼도 Service 클래스의 영향을 최소화 시킬 수 있다. - 결합도를 낮춰 유지보수의 효율성이 증가한다.
package xyz.itwill05.di;

import java.util.List;

public class StudentServiceImpl implements StudentService {
	//StudentJdbcDAO 클래스로 필드 선언 - StudentJdbcDAO 객체만 저장 가능한 필드
	// => 결합도가 높아 유지보수의 효율성 감소
	//private StudentJdbcDAO studentJdbcDAO;

	//StudentDAO 인터페이스로 필드 선언 - StudentDAO 인터페이스를 상속받은 자식클래스로 생성된 모든 객체 저장
	// => DAO 클래스가 변경돼도 Service 클래스의 영향 최소화 - 결합도를 낮춰 유지보수의 효율성 증가
	private StudentDAO studentDAO;
	
	public StudentServiceImpl() {
		System.out.println("### StudentServiceImpl 클래스의 기본 생성자 호출 ###");
	}
	
	public StudentServiceImpl(StudentDAO studentDAO) {
		super();
		this.studentDAO = studentDAO;
		System.out.println("### StudentServiceImpl 클래스의 매개변수가 선언된 생성자 호출 ###");
	}

	public StudentDAO getStudentDAO() {
		return studentDAO;
	}

	public void setStudentDAO(StudentDAO studentDAO) {
		this.studentDAO = studentDAO;
		System.out.println("*** StudentServiceImpl 클래스의 setStudentDAO(StudentDAO studentDAO) 메소드 호출 ***");
	}

	@Override
	public void addStudent(Student student) {
		System.out.println("*** StudentServiceImpl 클래스의 addStudent(Student student) 메소드 호출 ***");
		studentDAO.insertStudent(student);
	}

	@Override
	public void modifyStudent(Student student) {
		System.out.println("*** StudentServiceImpl 클래스의 modifyStudent(Student student) 메소드 호출 ***");
		studentDAO.updateStudent(student);
	}

	@Override
	public void removeStudent(int num) {
		System.out.println("*** StudentServiceImpl 클래스의 removeStudent(int num) 메소드 호출 ***");
		studentDAO.deleteStudent(num);
	}

	@Override
	public Student getStudent(int num) {
		System.out.println("*** StudentServiceImpl 클래스의 getStudent(int num) 메소드 호출 ***");
		return studentDAO.selectStudent(num);
	}

	@Override
	public List<Student> getStudentList() {
		System.out.println("*** StudentServiceImpl 클래스의 getStudentList() 메소드 호출 ***");
		return studentDAO.selectStudentList();
	}
}

 

DAO클래스와 Service 클래스를 Springn Bean으로 등록해주자

 

[05-1_di.xml]

<!-- StudentDAO 인터페이스를 상속받은 자식클래스(DAO 클래스)를 Spring Bean으로 등록 -->
<bean class="xyz.itwill05.di.StudentJdbcDAO" id="studentJdbcDAO"/>
	
<!-- StudentDAO 인터페이스를 상속받은 자식클래스(Service 클래스)를 Spring Bean으로 등록 -->
<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentServiceImpl"/>

 

클래스의 기본 생성자를 이용해 객체를 생성하기 때문에 객체 필드에는 기본값이 저장된다.

 

문제점)

[StudentServiceImpl] 클래스로 생성된 객체의 studentDAO 필드에는 [null]이 저장되어 studentServiceImpl 클래스의 메소드에서 필드로 메소드를 호출할 경우 NullPointerException이 발생한다 - 포함관계(의존관계) 미구현 

 

해결법)

StudentServiceImpl 클래스로 생성된 객체의 studentDAO 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체가 저장되도록 설정하는 것이다. 이를 통해 포함(의존)관계가 구현될 수 있도록 해야한다.

 


이번엔 StudentServiceImpl 클래스의 매개변수가 선언된 생성자를 이용하여 객체를 생성해보자

→ 생성자 매개변수에 StudentDAO 인터페이스를 상속받은 자식클래스(StudentJdbcDAO)의 객체를 전달하여 studentDAO 필드에 저장 - Constructor Injection 

 

constructor-arg 엘리먼트를 사용하여 StudentServiceImpl 클래스가 객체로 생성될 때 생성자 매개변수에 StudentJdbcDAO 객체를 전달하여 필드에 저장해준다. (의존관계가 구현된다) 

 

<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentServiceImpl">
	<constructor-arg ref="studentJdbcDAO"/>
</bean>

 

여기서 사용한 ref 속성에는 스프링 컨테이너로 관리되는 Spring Bean의 식별자(beanName)을 속성값으로 설정하면 된다.

→ 스프링 컨테이너에게 Spring Bean을 제공받아 객체 필드에 저장한다. 이를 의존성 주입(DI)라고 한다.

 


 

이번엔 Setter Injection을 사용해보자

 

클래스의 기본 생성자를 이용하여 객체를 생성한다. - 객체 필드에는 기본값이 저장된다.

→ Setter 메소드를 호출하여 StudentDAO 인터페이스를 상속받은 자식클래스(DAO 클래스)의 객체를 필드에 저장할 수 있도록 한다. - Setter Injection

 

property 엘리먼트를 사용하여 StudentServiceImpl 객체의 필드에 대한 Setter 메소드를 호출하여 StudentDAO 인터페이스를 상속받은 자식클래스의 객체를 필드에 저장한다. - 의존관계 구현 

<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentServiceImpl">
	<property name="studentDAO" ref="studentJdbcDAO"/>
</bean>

[StudentApp]

		//프로그램 실행에 필요한 데이터 처리 기능을 제공하는 Service 객체를 제공받아 저장 
		//StudentServiceImpl service=context.getBean("StudentServiceImple", StudentServiceImpl.class);
		
		//클래스로 참조변수(필드)를 생성하여 객체를 저장하는 것보다 인터페이스로 참조변수(필드)를 
		//생성하여 객체를 저장하는 것이 유지보수의 효율성을 증가하는 방법이다.
		StudentService service=context.getBean("studentServiceImpl", StudentService.class);
		
		//Service 객체의 메소드를 호출하여 필요한 데이처 처리 기능을 구현
		service.addStudent(student1);
		service.modifyStudent(student1);
		service.removeStudent(1000);
		service.getStudent(1000);
		service.getStudentList();

 

 

 

의존성 주입을 사용하면 좋은점은 Service 클래스에서 사용하던 DAO 클래스의 객체가 변경돼도 Service 클래스를 변경하지 않고 Spring Bean Configuration File만 수정해도 객체와의 의존관계를 변경할 수 있다는 것이다.

 

이를 통해 객체간의 결합도를 가장 느슨하게 만들어줄 수 있으며, 유지보수의 효율성이 높아진다. 

 

예제)

 

DAO를 [StudentMybatisDAO] 로 바꾸어보자

package xyz.itwill05.di;

import java.util.List;

public class StudentMybatisDAO implements StudentDAO {
	public StudentMybatisDAO() {
		System.out.println("### StudentMybatisDAO 클래스의 기본 생성자 호출 ###");
	}
	
	@Override
	public int insertStudent(Student student) {
		System.out.println("*** StudentMybatisDAO 클래스의 insertStudent(Student student) 메소드 호출 ***");
		return 0;
	}

	@Override
	public int updateStudent(Student student) {
		System.out.println("*** StudentMybatisDAO 클래스의 updateStudent(Student student) 메소드 호출 ***");
		return 0;
	}

	@Override
	public int deleteStudent(int num) {
		System.out.println("*** StudentMybatisDAO 클래스의 deleteStudent(int num) 메소드 호출 ***");
		return 0;
	}

	@Override
	public Student selectStudent(int num) {
		System.out.println("*** StudentMybatisDAO 클래스의 selectStudent(int num) 메소드 호출 ***");
		return null;
	}

	@Override
	public List<Student> selectStudentList() {
		System.out.println("*** StudentMybatisDAO 클래스의 selectStudentList() 메소드 호출 ***");
		return null;
	}
}

 

 Spring Bean Configuration File만 수정해도 객체와의 의존관계를 변경할 수 있다

 

...
<!-- StudentDAO 인터페이스를 상속받은 자식클래스(DAO 클래스)를 Spring Bean으로 등록 -->
<bean class="xyz.itwill05.di.StudentMybatisDAO" id="studentMybatisDAO"/>

<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentServiceImpl">
	<!-- <property name="studentDAO" ref="studentJdbcDAO"/> -->
	<property name="studentDAO" ref="studentMybatisDAO"/>
</bean>
...