[Spring 5-2] Dependency Injection - 의존성 주입

임승현·2023년 2월 14일

Spring

목록 보기
13/46

🌈인터페이스 생성

📢학생정보를 처리하는 DAO 클래스가 반드시 상속받아야 되는 인터페이스
→ 객체간의 결합도를 낮추어 유지보수의 효율성 증가

📃StudentDAO.java(인터페이스)

※ xyz.itwill05.di 패키지에 StudentDAO.java 인터페이스 생성

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 클래스 생성

📢DAO 클래스 : 저장매체(File, DBMS 등)에 대한 행 삽입,변경,삭제,검색 기능을 제공하는 클래스
→ 저장매체의 종류 또는 방법에 따라 DAO 클래스 변경 가능
→ DAO 클래스가 변경돼도 DAO 클래스와 관계가 있는 클래스(Service 클래스)에 영향을 최소화하기 위해 인터페이스를 상속받아 작성 - 결합도를 낮춰 유지보수 효율성 증가

📃StudentJdbcDAO.java(클래스)

※ xyz.itwill05.di 패키지에 StudentJdbcDAO.java 클래스 생성

package xyz.itwill05.di;
//
import java.util.List;
//
//DAO 클래스 : 저장매체(File, DBMS 등)에 대한 행 삽입,변경,삭제,검색 기능을 제공하는 클래스
//→ 저장매체의 종류 또는 방법에 따라 DAO 클래스 변경 가능
//→ DAO 클래스가 변경돼도 DAO 클래스와 관계가 있는 클래스(Service 클래스)에 영향을 최소화하기 위해 인터페이스를 상속받아 작성 - 결합도를 낮춰 유지보수 효율성 증가
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 클래스가 반드시 상속받아야 되는 인터페이스

📃StudentService.java(인터페이스)

※ xyz.itwill05.di 패키지에 StudentService.java 인터페이스 생성

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.java(클래스)

※ xyz.itwill05.di 패키지에 StudentServiceImpl.java 클래스 생성

package xyz.itwill05.di;
//
import java.util.List;
//
//Service 클래스 : 프로그램 실행에 필요한 데이터 처리 기능을 모듈화하여 제공하는 클래스 - 컴퍼넌트
//→ Service 클래스의 메소드는 DAO 클래스의 메소드를 호출하여 데이터 처리 기능 제공 - 모듈화
//→ DAO 클래스는 Service 클래스와 포함관계(의존관계)로 설정되도록 작성
//→ Service 클래스가 변경돼도 Service 클래스와 관계가 있는 클래스(모델 클래스)에 영향을 최소화하기 위해 인터페이스를 상속받아 작성 - 결합도를 낮춰 유지보수 효율성 증가
public class StudentServiceImpl implements StudentService {
	//StudentJdbcDAO 객체를 저장하기 위한 필드
	//→ 필드에 StudentJdbcDAO 객체를 저장해야만 포함관계가 성립
	//→ StudentServiceImpl 클래스의 메소드에서 StudentJdbcDAO 객체의 메소드 호출 가능
	//문제점) DAO 클래스가 변경될 경우 Service 클래스의 필드 및 메소드 변경
	//→ 결합도가 높아 유지보수 효율성 감소
	//private StudentJdbcDAO studentJdbcDAO;//비권장
	//해결법) DAO 클래스가 반드시 상속받아야 되는 인터페이스로 필드 선언
	//→ 필드에는 인터페이스를 상속받은 모든 DAO 클래스의 객체 저장 가능
	//
	//StudentDAO 인터페이스를 상속받은 모든 DAO 클래스의 객체를 저장할 수 있는 필드
	//→ StudentDAO 인터페이스를 상속받은 DAO 클래스의 객체를 저장해야만 의존관계 성립
	//→ Service 클래스의 메소드에서 필드로 메소드를 호출하면 필드에 저장된 자식 객체의 메소드 호출 - 오버라이딩에 의한 다형성 : 결합도를 낮춰 유지보수의 효율성 증가
	//→ 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();
	}
}

🌈환경설정파일 작성

📃05-1_di.xml

※ src/main/resources 폴더에 05-1_di.xml에 코드 작성

<!-- Student 인터페이스를 상속받아 자식클래스를 Spring Bean으로 등록 -->
<bean class="xyz.itwill05.di.StudentJdbcDAO" id="studentJdbcDAO"/>
<bean class="xyz.itwill05.di.StudentMybatisDAO" id="studentMybatisDAO"/>
<!--  -->
<!-- StudentService 인터페이스를 상속받아 자식클래스를 Spring Bean으로 등록 -->
<!-- → 클래스의 기본 생성자를 이용하여 객체 생성 - 객체 필드에는 기본값 저장 -->
<!-- 문제점) StudentServiceImpl 클래스로 생성된 객체의 필드에는 [null]이 저장되어 StudentServiceImpl 클래스의 
	메소드에서 StudentDAO 클래스의 메소드를 호출하면 NullPointerExcetion 발생 - 의존관계 미성립 -->
<!-- <bean class="xyz.itwill05.di.StudentServiceImpl" id="studentServiceImpl"></bean> -->
<!-- 해결법) StudentServiceImpl 클래스의 객체 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체가 저장되도록 설정 - 의존관계 성립 -->
<!--  -->
<!-- StudentServiceImpl 클래스의 매개변수가 선언된 생성자를 이용하여 객체 생성 -->
<!-- → 생성자 매개변수에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체 전달하여 필드에 저장 - Construction Injection -->
<!-- constructor-arg 엘리먼트를 사용하여StudentServiceImpl 클래스의 객체 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체 저장 - 의존관계 성립 -->
<!-- ref 속성 : 스프링 컨테이너로 관리되는 Spring Bean의 식별자를 속성값으로 설정 -->
<!-- → 스프링 컨테이너로 관리되는 Spring Bean을 객체 필드에 저장 - 의존성 주입(DI : Dependency Injection) -->
<!--  
<bean class="xyz.itwill05.di.StudentServiceImpl">
	<constructor-arg ref="studentJdbcDAO"/>
</bean>
-->
<!--  -->
<!-- StudentServiceImpl 클래스의 기본 생성자를 이용하여 객체를 생성 -->
<!-- → Setter 메소드를 호출하여 객체 필드에 StudentDAO 인터페이스를 상속받은 자식 클래스의 객체를 필드에 저장 >> Setter Injection -->
<!-- property 엘리먼트를 사용하여 StudentServiceImpl 클래스의 객체 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체 저장 - 의존관계 성립 -->
<!--  
<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentServiceImpl">
	<property name="studentDAO" ref="studentJdbcDAO"></property>
</bean>
-->
<!-- 기존에 사용하던 StudentJdbcDAO 클래스 대신 새롭게 작성한 StudentMybatisDAO 클래스로 의존관계를 변경하고자 할 경우 ref 속성값만 변경 -->
<!-- 기존 클래스 대신 새로운 클래스로 바꿔도 관계가 설정된 클래스를 변경하지 않고 Spring Bean Configuration File만 수정해도 의존관계 변경 - 유지보수 효율성 증가 -->
<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentServiceImpl">
	<property name="studentDAO" ref="studentMybatisDAO"></property>
</bean>

🌈프로그램 생성

📃StudentApp.java(클래스)

※ xyz.itwill05.di 패키지에 StudentApp.java에 코드 작성

//프로그램 실행에 필요한 데이터 처리 기능은 Service 클래스의 메소드를 호출하여 사용
//→ 스프링 컨테이너에게 Service 클래스의 객체를 제공받아 메소드 호출
//StudentServiceImpl service=context.getBean("studentServiceImpl", StudentServiceImpl.class);
//
//클래스로 참조변수를 생성하여 객체를 반환받아 저장하는 것보다는 인터페이스로 참조변수를 생성하여 객체를 저장하는 것이 유지보수의 효율성 증가
//→ 인터페이스로 반환받기 위한 객체의 형변환 가능
StudentService service=context.getBean("studentServiceImpl", StudentServiceImpl.class);
//
service.addStudent(student1);
service.modifyStudent(student1);
service.removeStudent(1000);
service.getStudent(100);
service.getStudentList();

🌈클래스 생성

📃StudentMybatisDAO.java(클래스)

※ xyz.itwill05.di 패키지에 StudentMybatisDAO.java 클래스 생성

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;
	}
}

0개의 댓글