Dependency 관리 (Injection, Collection, Annotation)

woom·2023년 2월 14일
0

Framework

목록 보기
8/20
post-thumbnail

🌼 Spring Injection

  • Spring Injection : 스프링 컨테이너에 의해 Spring Bean Configuration File에 등록된 클래스로 객체(Spring Bean) 생성시 필드에 원하는 값 또는 객체를 저장되도록 설정

    • 생성자(Constructor Injection) 또는 Setter 메소드(Setter Injection)를 이용하여 값 또는 객체를 필드에 저장

🐣 VO 클래스

  • 학생정보를 저장하기 위한 클래스
    • VO 클래스(DTO 클래스)

package xyz.itwill05.di;

public class Student {
	private int num;
	public String name;
	public String email;
	
	public Student() {
		System.out.println("### Student 클래스의 기본 생성자 호출 ###");
	}

	public Student(int num) {
		super();
		this.num = num;
		System.out.println("### Student 클래스의 매개변수(학번)가 선언된 생성자 호출 ###");
	}
	
	/*
	public Student(String name) {
		super();
		this.name = name;
		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) 메소드 호출 ***");
	}
	
	@Override
	public String toString() {
		return "학번 = "+num+", 이름 = "+name+", 이메일 = "+email;
	}
}





📕 환경설정파일 (Value Injection)

  • Spring Bean으로 등록된 클래스의 기본 생성자를 이용하여 객체 생성
    • 객체의 필드에는 기본값(숫자형 : 0, 논리형 : false, 참조형 : null) 저장
  • Spring Bean으로 등록된 클래스의 매개변수가 선언된 생성자를 이용하여 객체 생성
    • bean 엘리먼트의 하위 엘리먼트를 사용하여 생성자 매개변수에 값을 전달하여 필드값으로 저장
  • Constructor Injection : 생성자를 이용하여 객체 필드 초기화 작업 실행

    • constructor-arg : Spring Bean으로 등록된 클래스의 생성자 매개변수에 값(객체)을 전달하기 위한 엘리먼트
    • constructor-arg 엘리먼트의 갯수만큼 매개변수가 선언된 생성자를 반드시 작성
    • value 속성 : 매개변수에 전달하기 위한 값을 속성값으로 설정
    • Spring Bean으로 등록된 클래스가 객체로 생성될 때 필드에 전달값 저장
    • constructor-arg 엘리먼트의 작성순서에 의해 매개변수에 값(객체)이 전달되어 객체 초기화
  • Value Injection : 객체의 필드에 값이 저장되도록 초기화 작업 실행 (값 주입)

    • 전달값은 기본적으로 문자열(String 객체)로 전달 (매개변수의 자료형에 의해 자동 형변환)
    • 매개변수의 자료형에 의해 자동 형변환될 경우 NumberFormatException 발생 가능
  • index 속성 : 생성자 매개변수에 값(객체)을 전달하기 위한 순서를 속성값으로 설정

    • index 속성값은 0부터 1씩 증가되는 정수값 사용
    • <constructor-arg value="홍길동" index="1"/>
  • Setter Injection
    • 클래스의 기본 생성자를 이용하여 객체 생성 (객체 필드에는 기본값 저장)
    • 하위 엘리먼트 사용하여 Setter 메소드를 호출해 필드값 변경
  • property : 객체의 Setter 메소드를 호출하여 필드값을 변경하는 엘리먼트

    • name 속성 : 필드값을 변경하기 위한 필드명을 속성값으로 설정 (자동 완성 기능 사용 가능)
    • name 속성값으로 설정된 필드에 대한 Setter 메소드를 호출하여 필드값 변경
    • 필드에 대한 Setter 메소드가 없거나 잘못 선언된 경우 예외 발생
    • value 속성 : 필드에 저장된 값을 속성값으로 설정 (값 주입)
    • <property name="email" value="xyz@itwill.xyz"/>
  • 생성자(Constructor Injection)와 Setter 메소드(Setter Injection)를 같이 사용하여 객체 초기화 작업 가능
  • PropertyPlaceholderConfigurer 클래스 : Properties 파일을 제공받아 파일에 설정된 값을 Spring Bean Configuration File에서 사용할 수 있도록 제공하는 클래스
    • locations 필드에 Properties 파일의 경로를 전달하여 저장
    • Properties 파일에 의해 제공되는 값은 Spring Bean Configuration File에서 ${이름}으로 사용
  • Spring 5.2 이상에서는 PropertySourcesPlaceholderConfigurer 클래스를 사용하여 Properties 파일을 제공받아 Spring Bean Configuration File에서 사용할 수 있도록 변경
    • <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    • <property name="locations" value="xyz/itwill05/di/student.properties"/>(파일경로로 작성)
    • <property name="num" value="${num}"/>


<?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">

	<!-- Spring Bean으로 등록된 클래스의 기본 생성자를 이용하여 객체 생성 -->
	<!-- => 객체의 필드에는 기본값(숫자형 : 0, 논리형 : false, 참조형 : null) 저장 -->
	<bean class="xyz.itwill05.di.Student" id="student1"/>
	
	<!-- Spring Injection : 스프링 컨테이너에 의해 Spring Bean Configuration File에 등록된
	클래스로 객체(Spring Bean) 생성시 필드에 원하는 값 또는 객체를 저장되도록 설정 -->
	<!-- => 생성자(Constructor Injection) 또는 Setter 메소드(Setter Injection)를 이용하여 값 
	또는 객체를 필드에 저장 -->
	
	<!-- Spring Bean으로 등록된 클래스의 매개변수가 선언된 생성자를 이용하여 객체 생성 -->
	<!-- => bean 엘리먼트의 하위 엘리먼트를 사용하여 생성자 매개변수에 값을 전달하여 필드값으로 저장 -->
	<!-- => Constructor Injection : 생성자를 이용하여 객체 필드 초기화 작업 실행 -->
	<bean class="xyz.itwill05.di.Student" id="student2">
		<!-- constructor-arg : Spring Bean으로 등록된 클래스의 생성자 매개변수에 값(객체)을 
		전달하기 위한 엘리먼트 -->
		<!-- => constructor-arg 엘리먼트의 갯수만큼 매개변수가 선언된 생성자를 반드시 작성 -->
		<!-- value 속성 : 매개변수에 전달하기 위한 값을 속성값으로 설정 -->
		<!-- => Spring Bean으로 등록된 클래스가 객체로 생성될 때 필드에 전달값 저장 -->
		<!-- => Value Injection : 객체의 필드에 값이 저장되도록 초기화 작업 실행 - 값 주입 -->
		<!-- => 전달값은 기본적으로 문자열(String 객체)로 전달 - 매개변수의 자료형에 의해 자동 형변환 -->
		<!-- => 매개변수의 자료형에 의해 자동 형변환될 경우 NumberFormatException 발생 가능 -->
		<constructor-arg value="1000"/>
	</bean>
	
	<!-- constructor-arg 엘리먼트의 작성순서에 의해 매개변수에 값(객체)이 전달되어 객체 초기화 -->
	<!-- 
	<bean class="xyz.itwill05.di.Student" id="student3">
		<constructor-arg value="2000"/>
		<constructor-arg value="홍길동"/>
		<constructor-arg value="abc@itwill.xyz"/>
	</bean>
	-->
	
	<bean class="xyz.itwill05.di.Student" id="student3">
		<!-- index 속성 : 생성자 매개변수에 값(객체)을 전달하기 위한 순서를 속성값으로 설정 -->
		<!-- => index 속성값은 0부터 1씩 증가되는 정수값 사용 -->		
		<constructor-arg value="홍길동" index="1"/>
		<constructor-arg value="abc@itwill.xyz" index="2"/>
		<constructor-arg value="2000" index="0"/>
	</bean>
	
	<!-- 클래스의 기본 생성자를 이용하여 객체 생성 - 객체 필드에는 기본값 저장 -->
	<!-- => 하위 엘리먼트 사용하여 Setter 메소드를 호출해 필드값 변경 - Setter Injection -->
	<bean class="xyz.itwill05.di.Student" id="student4">
		<!-- property : 객체의 Setter 메소드를 호출하여 필드값을 변경하는 엘리먼트 -->
		<!-- name 속성 : 필드값을 변경하기 위한 필드명을 속성값으로 설정 - 자동 완성 기능 사용 가능 -->
		<!-- => name 속성값으로 설정된 필드에 대한 Setter 메소드를 호출하여 필드값 변경 -->
		<!-- => 필드에 대한 Setter 메소드가 없거나 잘못 선언된 경우 예외 발생 -->
		<!-- value 속성 : 필드에 저장된 값을 속성값으로 설정 - 값 주입 -->
		<property name="num" value="3000"/>
		<property name="name" value="임꺽정"/>
		<property name="email" value="xyz@itwill.xyz"/>
	</bean>
	
	<!-- 생성자(Constructor Injection)와 Setter 메소드(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 클래스 : Properties 파일을 제공받아 파일에 설정된
	값을 Spring Bean Configuration File에서 사용할 수 있도록 제공하는 클래스 -->
	<!-- => locations 필드에 Properties 파일의 경로를 전달하여 저장 -->
	<!-- => Properties 파일에 의해 제공되는 값은 Spring Bean Configuration File에서 ${이름}으로 사용 -->
	<!--  
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations" value="xyz/itwill05/di/student.properties"/>
	</bean>
	-->
	
	<!-- Spring 5.2 이상에서는 PropertySourcesPlaceholderConfigurer 클래스를 사용하여
	Properties 파일을 제공받아 Spring Bean Configuration File에서 사용할 수 있도록 변경 -->
	<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
		<property name="locations" value="xyz/itwill05/di/student.properties"/>
	</bean>
	
	<!-- Properties 파일에 의해 제공되는 값을 사용하여 객체 필드 초기화 작업 -->
	<bean class="xyz.itwill05.di.Student" id="student6">
		<property name="num" value="${num}"/>
		<property name="name" value="${name}"/>
		<property name="email" value="${email}"/>
	</bean>
</beans>





🐣 앱 실행

  • 참조변수 출력시 Student 클래스의 toString() 메소드 자동 호출

    • 객체의 필드값 확인

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);
		//참조변수 출력시 Student 클래스의 toString() 메소드 자동 호출 - 객체의 필드값 확인
		System.out.println(student1);
		System.out.println("================================================================");
		Student student2=context.getBean("student2",Student.class);
		System.out.println(student2);
		System.out.println("================================================================");
		Student student3=context.getBean("student3",Student.class);
		System.out.println(student3);
		System.out.println("================================================================");
		Student student4=context.getBean("student4",Student.class);
		System.out.println(student4);
		System.out.println("================================================================");
		Student student5=context.getBean("student5",Student.class);
		System.out.println(student5);
		System.out.println("================================================================");
		Student student6=context.getBean("student6",Student.class);
		System.out.println(student6);
		System.out.println("================================================================");
		((ClassPathXmlApplicationContext)context).close();
	}
}





💡 Student Properties

  • 한글 입력 시 자동으로 유니코드로 저장됨
#Student Properties
num = 5000
name = \uC77C\uC9C0\uB9E4
email = il@itwill.xyz




🌼 Dependency Injection

  • DI : Dependency Injection(의존성 주입)

    • Dependency 관리 : Spring에서 Framework가 관리하는 Bean을 다른 Bean에서 사용할 수 있도록 설정해주는 역할까지 대행하는 것
  • 스프링 컨테이너로 관리되는 Spring Bean을 객체 필드에 저장


🌸 interface (DAO)

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

package xyz.itwill05.di;

import java.util.List;

public interface StudentDAO {
	int insertStudent(Student student);
	int updateStudent(Student student);
	int deleteStudent(int num);
	Student selectStudent(int num);
	List<Student> selectStudentList();
}





📙 DAO클래스1 (interface 상속)

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

    • 저장매체의 종류 또는 방법에 따라 DAO 클래스 변경 가능
    • DAO 클래스가 변경돼도 DAO 클래스와 관계가 있는 클래스(Service 클래스)에 영향을 최소화하기 위해 반드시 인터페이스 상속받아 작성
    • 결합도를 낮춰 유지보수의 효율성 증가

package xyz.itwill05.di;

import java.util.List;

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





📙 DAO클래스2 (interface 상속)



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





🌸 interface (Service)

  • 학생정보를 처리하는 Service 클래스가 반드시 상속받아야 되는 인터페이스

package xyz.itwill05.di;

import java.util.List;

public interface StudentService {
	void addStudent(Student student);
	void modifyStudent(Student student);
	void removeStudent(int num);
	Student getStudent(int num);
	List<Student> getStudentList();
}





📒 Service 클래스 (interface 상속)

  • Service 클래스 : 프로그램 실행에 필요한 데이타 처리 기능을 모듈화하여 제공하는 클래스 (컴퍼넌트)
    • Service 클래스의 메소드는 다수의 DAO 클래스의 메소드를 호출하여 작성 (모듈화)
    • DAO 클래스는 Service 클래스와 포함관계(의존관계)로 설정되도록 작성
    • 포함관계 중에서 의존도가 높지 않은 관계 : 의존관계 (ex. TV와 리모콘)
    • Service 클래스가 변경돼도 Service 클래스와 관계가 있는 클래스(모델 클래스)에 영향을 최소화하기 위해 반드시 인터페이스 상속받아 작성
    • 결합도를 낮춰 유지보수의 효율성 증가
  • StudentJdbcDAO 객체를 저장하기 위한 필드

    • 필드에 StudentJdbcDAO 객체를 저장해야만 의존관계가 성립
    • StudentServiceImpl 클래스의 메소드에서 StudentJdbcDAO 객체의 메소드 호출 가능
    • 문제점) DAO 클래스가 변경될 경우 Service 클래스의 필드 및 메소드 변경 결합도가 높아 유지보수의 효율성 감소
    • 해결법) DAO 클래스가 반드시 상속받아야 되는 인터페이스로 필드 선언
    • 필드에는 인터페이스를 상속받은 모든 DAO 클래스의 객체 저장 가능
  • StudentDAO 인터페이스를 상속받은 모든 DAO 클래스의 객체를 저장할 수 있는 필드
    • StudentDAO 인터페이스를 상속받은 DAO 클래스의 객체를 저장해야만 의존관계 성립
    • Service 클래스의 메소드에서 필드로 추상메소드를 호출하여 필드에 저장된 자식 객체의 메소드 호출
    • 오버라이딩에 의한 다형성 : 결합도를 낮춰 유지보수의 효율성 증가
    • DAO 클래스가 변경돼도 Service 클래스의 영향 최소화
    • private StudentDAO studentDAO;


package xyz.itwill05.di;

import java.util.List;

public class StudentServiceImpl implements StudentService {
	//StudentJdbcDAO 객체를 저장하기 위한 필드
	// => 필드에 StudentJdbcDAO 객체를 저장해야만 의존관계가 성립 
	// => StudentServiceImpl 클래스의 메소드에서 StudentJdbcDAO 객체의 메소드 호출 가능
	//문제점)DAO 클래스가 변경될 경우 Service 클래스의 필드 및 메소드 변경 
	// => 결합도가 높아 유지보수의 효율성 감소
	//해결법)DAO 클래스가 반드시 상속받아야 되는 인터페이스로 필드 선언
	// => 필드에는 인터페이스를 상속받은 모든 DAO 클래스의 객체 저장 가능
	//private StudentJdbcDAO studentJdbcDAO;
	
	//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();
	}
}





📕 환경설정파일 (DI)

  • StudentDAO 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록

  • StudentService 인터페이스를 상속받아 자식클래스를 Spring Bean으로 등록

    • 클래스의 기본 생성자를 이용하여 객체 생성 (객체 필드에는 기본값 저장)
    • 문제점) StudentServiceImpl 클래스로 생성된 객체의 필드에는 [null]이 저장되어 StudentServiceImpl클래스의 메소드에서 StudentDAO 클래스의 메소드를 호출하면 NullPointerExcetion 발생 → 의존관계 미성립
    • 해결법) StudentServiceImpl 클래스의 객체 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체가 저장되도록 설정 → 의존관계 성립
  • StudentServiceImpl 클래스의 매개변수가 선언된 생성자를 이용하여 객체 생성

    • 생성자 매개변수에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체를 전달하여 필드에 저장 (Constructor Injection)
    • constructor-arg 엘리먼트를 사용하여 StudentServiceImpl 클래스의 객체 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체 저장 → 의존관계 성립
      -ref 속성 : 스프링 컨테이너로 관리되는 Spring Bean의 식별자를 속성값으로 설정
    • 스프링 컨테이너로 관리되는 Spring Bean을 객체 필드에 저장 : 의존성 주입(DI : Dependency Injection)
    • <bean class="xyz.itwill05.di.StudentServiceImpl" id="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"/>
      			</bean>
  • 기존에 사용하던 StudentJdbcDAO 클래스 대신 새롭게 작성한 StudentMybatisDAO 클래스로 의존관계를 변경하고자 할 경우 ref 속성값만 변경

    • 기존 클래스 대신 새로운 클래스로 바꿔도 관계가 설정된 클래스를 변경하지 않고 Spring Bean Configuration File만 수정해도 의존관계 변경 → 유지보수의 효율성 증가


<?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">

	<!-- StudentDAO 인터페이스를 상속받은 자식클래스를 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 발생 - 의존관계 미성립 -->
	<!-- 해결법)StudentServiceImpl 클래스의 객체 필드에 StudentDAO 인터페이스를 상속받은
	자식클래스의 객체가 저장되도록 설정 - 의존관계 성립 -->
	<!-- <bean class="xyz.itwill05.di.StudentServiceImpl" id="studentServiceImpl"/> -->

	<!-- StudentServiceImpl 클래스의 매개변수가 선언된 생성자를 이용하여 객체 생성 -->
	<!-- => 생성자 매개변수에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체를 전달하여
	필드에 저장 - Constructor Injection -->
	<!-- constructor-arg 엘리먼트를 사용하여 StudentServiceImpl 클래스의 객체 필드에  
	StudentDAO 인터페이스를 상속받은 자식클래스의 객체 저장 - 의존관계 성립 -->
	<!-- ref 속성 : 스프링 컨테이너로 관리되는 Spring Bean의 식별자를 속성값으로 설정 -->
	<!-- => 스프링 컨테이너로 관리되는 Spring Bean을 객체 필드에 저장 - 의존성 주입(DI : Dependency Injection) -->
	<!--  
	<bean class="xyz.itwill05.di.StudentServiceImpl" id="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"/>
	</bean>
	-->
	
	<!-- 기존에 사용하던 StudentJdbcDAO 클래스 대신 새롭게 작성한 StudentMybatisDAO 클래스로
	의존관계를 변경하고자 할 경우 ref 속성값만 변경 -->
	<!-- => 기존 클래스 대신 새로운 클래스로 바꿔도 관계가 설정된 클래스를 변경하지 않고
	Spring Bean Configuration File만 수정해도 의존관계 변경 - 유지보수의 효율성 증가 -->
	<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentServiceImpl">
		<property name="studentDAO" ref="studentMybatisDAO"/>
	</bean>
</beans>





🐣 앱 실행

  • 프로그램 실행에 필요한 데이타 처리 기능은 Service 클래스의 메소드를 호출하여 사용

    • 스프링 컨테이너에게 Service 클래스의 객체를 제공받아 메소드 호출
  • 클래스로 참조변수를 생성하여 객체를 반환받아 저장하는 것보다는 인터페이스로 참조변수를 생성하여 객체를 저장하는 것이 유지보수의 효율성 증가
    • 인터페이스로 반환받기 위한 객체의 형변환 가능
    • StudentService service=context.getBean("studentServiceImpl", StudentService.class);

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);
		//참조변수 출력시 Student 클래스의 toString() 메소드 자동 호출 - 객체의 필드값 확인
		System.out.println(student1);
		System.out.println("================================================================");
		Student student2=context.getBean("student2",Student.class);
		System.out.println(student2);
		System.out.println("================================================================");
		Student student3=context.getBean("student3",Student.class);
		System.out.println(student3);
		System.out.println("================================================================");
		Student student4=context.getBean("student4",Student.class);
		System.out.println(student4);
		System.out.println("================================================================");
		Student student5=context.getBean("student5",Student.class);
		System.out.println(student5);
		System.out.println("================================================================");
		Student student6=context.getBean("student6",Student.class);
		System.out.println(student6);
		System.out.println("================================================================");
		//프로그램 실행에 필요한 데이타 처리 기능은 Service 클래스의 메소드를 호출하여 사용
		// => 스프링 컨테이너에게 Service 클래스의 객체를 제공받아 메소드 호출
		//StudentServiceImpl service=context.getBean("studentServiceImpl", StudentServiceImpl.class);
		
		//클래스로 참조변수를 생성하여 객체를 반환받아 저장하는 것보다는 인터페이스로 참조변수를
		//생성하여 객체를 저장하는 것이 유지보수의 효율성 증가
		// => 인터페이스로 반환받기 위한 객체의 형변환 가능
		StudentService service=context.getBean("studentServiceImpl", StudentService.class);
		
		service.addStudent(student1);
		service.modifyStudent(student1);
		service.removeStudent(1000);
		service.getStudent(100);
		service.getStudentList();
		System.out.println("================================================================");
		((ClassPathXmlApplicationContext)context).close();
	}
}






🌼 Collection 객체


🐣 CollectionBean 클래스

  • Collection 객체의 제네릭을 인터페이스로 설정하면 Collection 객체의 요소에는 인터페이스를 상속받은 모든 자식클래스의 객체 저장 가능

package xyz.itwill05.di;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class CollectionBean {
	private Set<String> nameSet;
	private List<String> nameList;
	//Collection 객체의 제네릭을 인터페이스로 설정하면 Collection 객체의 요소에는 인터페이스를
	//상속받은 모든 자식클래스의 객체 저장 가능
	private Set<Controller> controllerSet;
	private List<Controller> controllerList;
	private Map<String, Controller> controllerMap;
	private Properties controllerProperties;
	
	public CollectionBean() {
		System.out.println("### CollectionBean 클래스의 기본 생성자 호출 ###");
	}

	public Set<String> getNameSet() {
		return nameSet;
	}

	public void setNameSet(Set<String> nameSet) {
		this.nameSet = nameSet;
	}

	public List<String> getNameList() {
		return nameList;
	}

	public void setNameList(List<String> nameList) {
		this.nameList = nameList;
	}

	public Set<Controller> getControllerSet() {
		return controllerSet;
	}

	public void setControllerSet(Set<Controller> controllerSet) {
		this.controllerSet = controllerSet;
	}

	public List<Controller> getControllerList() {
		return controllerList;
	}

	public void setControllerList(List<Controller> controllerList) {
		this.controllerList = controllerList;
	}

	public Map<String, Controller> getControllerMap() {
		return controllerMap;
	}

	public void setControllerMap(Map<String, Controller> controllerMap) {
		this.controllerMap = controllerMap;
	}

	public Properties getControllerProperties() {
		return controllerProperties;
	}

	public void setControllerProperties(Properties controllerProperties) {
		this.controllerProperties = controllerProperties;
	}
}





🌸 interface

package xyz.itwill05.di;

public interface Controller {
	void handlRequest();
}




🐣 interface의 자식클래스

  • LoginController, LogoutController, ListController
package xyz.itwill05.di;

public class LoginController implements Controller {

	@Override
	public void handlRequest() {
		// TODO Auto-generated method stub
	}
}
package xyz.itwill05.di;

public class LogoutController implements Controller {

	@Override
	public void handlRequest() {
		// TODO Auto-generated method stub
	}
}
package xyz.itwill05.di;

public class ListController implements Controller {

	@Override
	public void handlRequest() {
		// TODO Auto-generated method stub
	}
}


📕 환경설정파일 (Controller)

  • set : Set 객체를 생성하여 필드에 저장하기 위한 엘리먼트 (순서X, 중복X)
    • value : Collection 객체에 요소값을 추가하는 엘리먼트
  • list : List 객체를 생성하여 필드에 저장하기 위한 엘리먼트 (순서O, 중복O)
  • ref : Collection 객체의 요소로 Spring Bean으로 등록된 클래스의 객체를 추가하기 위한 엘리먼트
    • bean 속성 : 요소로 추가될 Spring Bean의 식별자를 속성값으로 설정 (자동 완성 기능 사용 가능)
  • map : Map 객체를 생성하여 필드에 저장하기 위한 엘리먼트
    • entry : Map 객체에 엔트리(Entry - Key & Value)를 추가하기 위한 엘리먼트
    • key : 엔트리의 맵키(String)를 설정하기 위한 엘리먼트 (하위 엘리먼트 : value로 문자값으로 저장)
    • ref : 엔트리의 맵값(Controller 객체)를 설정하기 위한 엘리먼트
  • props : Properties 객체를 생성하여 필드에 저장하기 위한 엘리먼트
    • 필드의 자료형 Map<String,String>인 경우 props 엘리먼트로 객체 필드에 Map 객체를 생성하여 저장 가능
    • prop : Properties 객체에 엔트리를 추가하는 메소드
    • 엘리먼트의 내용으로 엔트리에 저장될 값(문자열)을 설정
    • key 속성 : 엔트리를 구분하기 위한 식별자(문자열)를 속성값으로 설정
    • <prop key="login">xyz.itwill05.di.LoginController</prop>


<?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">

	<!-- Controller 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록 -->
	<bean class="xyz.itwill05.di.LoginController" id="loginController"/>
	<bean class="xyz.itwill05.di.LogoutController" id="logoutController"/>
	<bean class="xyz.itwill05.di.ListController" id="listController"/>

	<bean class="xyz.itwill05.di.CollectionBean" id="collectionBean">
		<property name="nameSet">
			<!-- set : Set 객체를 생성하여 필드에 저장하기 위한 엘리먼트 -->
			<set>
				<!-- value : Collection 객체에 요소값을 추가하는 엘리먼트 -->
				<value>홍길동</value>
				<value>임꺽정</value>
				<value>전우치</value>
				<value>홍길동</value>
			</set>
		</property>
		
		<property name="nameList">
			<!-- list : List 객체를 생성하여 필드에 저장하기 위한 엘리먼트 -->
			<list>
				<value>홍길동</value>
				<value>임꺽정</value>
				<value>전우치</value>
				<value>홍길동</value>
			</list>
		</property>
		
		<property name="controllerSet">
			<set>
				<!-- Collection 객체의 요소로 Spring Bean으로 등록된 클래스의 객체를 추가하기 위한 엘리먼트 -->
				<!-- bean 속성 : 요소로 추가될 Spring Bean의 식별자를 속성값으로 설정 - 자동 완성 기능 사용 가능 -->
				<ref bean="loginController"/>
				<ref bean="logoutController"/>
				<ref bean="listController"/>
			</set>
		</property>
		
		<property name="controllerList">
			<list>
				<ref bean="loginController"/>
				<ref bean="logoutController"/>
				<ref bean="listController"/>
			</list>
		</property>
		
		<property name="controllerMap">
			<!-- map : Map 객체를 생성하여 필드에 저장하기 위한 엘리먼트 -->
			<map>
				<!-- entry : Map 객체에 엔트리(Entry - Key & Value)를 추가하기 위한 엘리먼트 -->
				<entry>
					<!-- key : 엔트리의 맵키(String)를 설정하기 위한 엘리먼트 -->
					<key>
						<value>login</value>
					</key> 
					<!-- ref : 엔트리의 맵값(Controller 객체)를 설정하기 위한 엘리먼트 -->
					<ref bean="loginController"/>
				</entry>
				<entry>
					<key>
						<value>logout</value>
					</key> 
					<ref bean="logoutController"/>
				</entry>
				<entry>
					<key>
						<value>list</value>
					</key> 
					<ref bean="listController"/>
				</entry>
			</map>
		</property>
		
		<property name="controllerProperties">
			<!-- props : Properties 객체를 생성하여 필드에 저장하기 위한 엘리먼트 -->
			<!-- => 필드의 자료형 Map<String,String>인 경우 props 엘리먼트로 객체 필드에 
			Map 객체를 생성하여 저장 가능 -->		
			<props>
				<!-- prop : Properties 객체에 엔트리를 추가하는 메소드 -->
				<!-- => 엘리먼트의 내용으로 엔트리에 저장될 값(문자열)을 설정 -->
				<!-- key 속성 : 엔트리를 구분하기 위한 식별자(문자열)를 속성값으로 설정 -->
				<prop key="login">xyz.itwill05.di.LoginController</prop>
				<prop key="logout">xyz.itwill05.di.LogoutController</prop>
				<prop key="list">xyz.itwill05.di.ListController</prop>
			</props>
		</property>
	</bean>
</beans>





🐣 앱 실행

  • CollectionBean 객체에 저장된 필드값을 반환받아 출력
    • Collection 객체의 toString() 메소드 자동 호출
    • Collection 객체에 저장된 모든 요소값이 문자열로 반환

package xyz.itwill05.di;

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

public class CollectionBeanApp {
	public static void main(String[] args) {
		System.out.println("================== Spring Container 초기화 전 ==================");
		ApplicationContext context=new ClassPathXmlApplicationContext("05-2_collection.xml");
		System.out.println("================== Spring Container 초기화 후 ==================");
		CollectionBean bean=context.getBean("collectionBean",CollectionBean.class);
		
		//CollectionBean 객체에 저장된 필드값을 반환받아 출력 
		// => Collection 객체의 toString() 메소드 자동 호출 - Collection 객체에 저장된 모든 요소값이 문자열로 반환 
		System.out.println("nameSet = "+bean.getNameSet());
		System.out.println("nameList = "+bean.getNameList());
		System.out.println("controllerSet = "+bean.getControllerSet());
		System.out.println("controllerList = "+bean.getControllerList());
		System.out.println("controllerMap = "+bean.getControllerMap());
		System.out.println("controllerPropertes = "+bean.getControllerProperties());
		System.out.println("================================================================");
		((ClassPathXmlApplicationContext)context).close();
	}
}





🌼 의존 관계 자동 설정

  • autowire : 스프링 컨테이너가 Spring Bean의 의존관계를 자동으로 구현되도록 설정하는 속성

    • 속성: no(기본), byName, byType, constructor 중 하나를 속성값으로 설정

📕 환경설정파일 (autowire)

  • StudentService 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록
    • StudentServiceImpl 클래스의 studentDAO 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체(Spring Bean)가 저장되도록 의존성 주입 (의존관계 성립)
    • 의존성 주입을 하지 않으면 StudentServiceImpl 클래스의 메소드에서 StudentDAO 인터페이스를 상속받은 자식클래스의 메소드를 호출할 경우 NullPointerException 발생 (기본생성자 호출)
    • property 엘리먼트를 사용하여 studentDAO 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 객체(Spring Bean)가 저장되도록 설정 (Setter Injection)
  • autowire 속성: no(기본), byName, byType, constructor 중 하나를 속성값으로 설정
  • no 속성값 : 자동으로 의존관계를 구현하는 기능 미사용

  • byName 속성값 : Spring Bean으로 등록된 클래스의 필드명과 같은 이름의 식별자(beanName)로 선언된 Spring Bean를 제공받아 필드에 저장되도록 의존성 주입 (Setter Injection)

    • 필드명과 같은 이름의 식별자(beanName)로 선언된 Spring Bean이 없는 경우 의존성 미주입 → NullPointerException 발생
  • byType 속성값 : Spring Bean으로 등록된 클래스의 필드와 같은 자료형의 Spring Bean을 제공받아 필드에 저장되도록 의존성 주입 (Setter Injection)

    • 필드의 자료형이 인터페이스인 경우 인터페이스를 상속받은 자식클래스로 등록된 Spring Bean의 객체를 제공받아 필드에 저장되도록 의존성 주입
    • 필드와 같은 자료형의 Spring Bean이 2개 이상 등록된 경우 의존성 주입 실패 → NoUniqueBeanDefinitionException 발생
  • constructor 속성값 : Spring Bean으로 등록된 클래스의 필드와 같은 자료형의 Spring Bean을 제공받아 필드에 저장되도록 의존성 주입 (Constructor Injection)

    • 필드의 자료형이 인터페이스인 경우 인터페이스를 상속받은 자식클래스로 등록된 Spring Bean의 객체를 제공받아 필드에 저장되도록 의존성 주입
    • 필드와 같은 자료형의 Spring Bean이 2개 이상 등록된 경우 기본 생성자로 객체 생성 (의존성 미주입)
    • 기본생성자와 매개변수가 포함된 생성자가 필수로 필요함


<?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">

	<!-- StudentDAO 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록 -->
	<bean class="xyz.itwill05.di.StudentJdbcDAO" id="studentJdbcDAO"/>
	<!-- <bean class="xyz.itwill05.di.StudentJdbcDAO" id="studentDAO"/> -->
	<bean class="xyz.itwill05.di.StudentMybatisDAO" id="studentMybatisDAO"/>
	
	<!-- StudentService 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록 -->
	<!-- => StudentServiceImpl 클래스의 studentDAO 필드에 StudentDAO 인터페이스를 상속받은
	자식클래스의 객체(Spring Bean)가 저장되도록 의존성 주입 - 의존관계 성립 -->
	<!-- => 의존성 주입을 하지 않으면 StudentServiceImpl 클래스의 메소드에서 StudentDAO
	인터페이스를 상속받은 자식클래스의 메소드를 호출할 경우 NullPointerException 발생 -->
	<!-- property 엘리먼트를 사용하여 studentDAO 필드에 StudentDAO 인터페이스를 상속받은 자식
	클래스의 객체(Spring Bean)가 저장되도록 설정 - Setter Injection -->
	<!--  
	<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentService">
		<property name="studentDAO" ref="studentJdbcDAO"/>
	</bean>
	-->
	
	<!-- autowire 속성: no(기본), byName, byType, constructor 중 하나를 속성값으로 설정 -->
	<!-- => 스프링 컨테이너가 Spring Bean의 의존관계를 자동으로 구현되도록 설정하는 속성 -->
	<!-- no 속성값 : 자동으로 의존관계를 구현하는 기능 미사용 -->
	<!--  
	<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentService" autowire="no">
		<property name="studentDAO" ref="studentJdbcDAO"/>
	</bean>
	-->
	
	<!-- byName 속성값 : Spring Bean으로 등록된 클래스의 필드명과 같은 이름의 식별자(beanName)로   
	선언된 Spring Bean를 제공받아 필드에 저장되도록 의존성 주입 - Setter Injection -->
	<!-- => 필드명과 같은 이름의 식별자(beanName)로 선언된 Spring Bean이 없는 경우 의존성 미주입 - NullPointerException 발생 -->
	<!-- <bean class="xyz.itwill05.di.StudentServiceImpl" id="studentService" autowire="byName"/> -->
	
	<!-- byType 속성값 : Spring Bean으로 등록된 클래스의 필드와 같은 자료형의 Spring Bean를
	제공받아 필드에 저장되도록 의존성 주입 - Setter Injection -->
	<!-- => 필드의 자료형이 인터페이스인 경우 인터페이스를 상속받은 자식클래스로 등록된
	Spring Bean의 객체를 제공받아 필드에 저장되도록 의존성 주입 -->
	<!-- => 필드와 같은 자료형의 Spring Bean이 2개 이상 등록된 경우 의존성 주입 실패 - NoUniqueBeanDefinitionException 발생 -->
	<!-- <bean class="xyz.itwill05.di.StudentServiceImpl" id="studentService" autowire="byType"/> -->

	<!-- constructor 속성값 : Spring Bean으로 등록된 클래스의 필드와 같은 자료형의 Spring Bean를
	제공받아 필드에 저장되도록 의존성 주입 - Constructor Injection -->
	<!-- => 필드의 자료형이 인터페이스인 경우 인터페이스를 상속받은 자식클래스로 등록된
	Spring Bean의 객체를 제공받아 필드에 저장되도록 의존성 주입 -->
	<!-- => 필드와 같은 자료형의 Spring Bean이 2개 이상 등록된 경우 기본 생성자로 객체 생성 - 의존성 미주입 -->
	<bean class="xyz.itwill05.di.StudentServiceImpl" id="studentService" autowire="constructor"/> 
</beans>





🐣 앱 실행

package xyz.itwill05.di;

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

public class AutoWireApp {
	public static void main(String[] args) {
		System.out.println("================== Spring Container 초기화 전 ==================");
		ApplicationContext context=new ClassPathXmlApplicationContext("05-3_autowire.xml");
		System.out.println("================== Spring Container 초기화 후 ==================");
		StudentService service=context.getBean("studentService",StudentService.class);
		service.addStudent(null);
		System.out.println("================================================================");
		((ClassPathXmlApplicationContext)context).close();		
	}
}





🌼 Annotation DI

  • 특정 Bean의 기능 수행을 위해 다른 Bean을 참조해야 하는 경우 사용하는 Annotation

📕 환경설정파일 (Annotation)

  • <context:component-scan base-package="xyz.itwill05.di"/> : xyz.itwill05.di 에서 어노테이션을 찾아 객체로 만들겠다
    • 작성하지 않으면 어노테이션 사용 불가

<?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:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	
	<context:component-scan base-package="xyz.itwill05.di"/>
</beans>





📙 DAO클래스1 (Annotation)

  • @Component : 클래스를 스프링 컨테이너가 관리할 수 있는 Spring Bean으로 등록하기 위한 어노테이션

    • 클래스의 이름을 beanName으로 자동 설정 (클래스의 이름에서 첫문자는 소문자로 변환)
    • @Component 어노테이션의 value 속성을 사용하여 beanName 변경 가능 (다른 속성이 없는 경우 속성값만 설정 가능)
  • @Repository : DAO 클래스를 스프링 컨테이너가 관리할 수 있는 Spring Bean으로 등록하기 위한 어노테이션

    • 클래스의 이름을 beanName으로 자동 설정하지만 value 속성으로 beanName 변경 가능
    • 트랜잭션 메니저에 의해 객체 관리
    • @Repository("studentDAO")
  • @Primary : 의존성을 주입하기 위한 우선권을 제공하기 위한 어노테이션

    • 동일 자료형의 클래스에 @Primary 어노테이션을 사용한 경우 의존성 주입 실패


package xyz.itwill05.di;

import java.util.List;

import org.springframework.stereotype.Repository;

//@Component : 클래스를 스프링 컨테이너가 관리할 수 있는 Spring Bean으로 등록하기 위한 어노테이션
// => 클래스의 이름을 beanName으로 자동 설정 - 클래스의 이름에서 첫문자는 소문자로 변환
// => @Component 어노테이션의 value 속성을 사용하여 beanName 변경 가능 - 다른 속성이 없는 경우 속성값만 설정 가능
//@Component

//@Repository : DAO 클래스를 스프링 컨테이너가 관리할 수 있는 Spring Bean으로 등록하기 위한 어노테이션
// => 클래스의 이름을 beanName으로 자동 설정하지만 value 속성으로 beanName 변경 가능
//@Repository("studentDAO")
@Repository
//@Primary : 의존성을 주입하기 위한 우선권을 제공하기 위한 어노테이션
// => 동일 자료형의 클래스에 @Primary 어노테이션을 사용한 경우 의존성 주입 실패
//@Primary
public class AnnotationStudentJdbcDAO implements StudentDAO {
	public AnnotationStudentJdbcDAO() {
		System.out.println("### AnnotationStudentJdbcDAO 클래스의 기본 생성자 호출 ###");
	}

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

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

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

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

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





📙 DAO클래스2



package xyz.itwill05.di;

import java.util.List;

import org.springframework.stereotype.Repository;

@Repository
public class AnnotationStudentMybatisDAO implements StudentDAO {
	public AnnotationStudentMybatisDAO() {
		System.out.println("### AnntationStudentMybatisDAO 클래스의 기본 생성자 호출 ###");
	}

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

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

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

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

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





📒 Service 클래스

  • @Service : Service 클래스를 스프링 컨테이너가 관리할 수 있는 Spring Bean으로 등록하기 위한 어노테이션

    • 클래스의 이름을 beanName으로 자동 설정하지만 value 속성으로 beanName 변경 가능
  • @Autowired : 스프링 컨테이너로부터 Spring Bean를 제공받아 필드에 저장되도록 의존관계를 자동으로 구현하기 위한 어노테이션

    • 의존성 주입을 위해 필드에 사용하는 어노테이션 (선언된 필드마다 어노테이션 설정)
    • bean 엘리먼트에서 autowire 속성값을 [byType]으로 설정한 것과 같은 방법으로 의존성 주입 (Setter Injection)
    • Setter 메소드를 이용하여 의존관계를 설정하지만 Setter 메소드를 작성하지 않아도 의존성 주입
    • 문제점) 필드의 자료형과 같은 자료형의 Spring Bean이 2개 이상 존재할 경우 의존성 주입 실패(NoUniqueBeanDefinitionException 발생)
  • 해결법1) 필드의 자료형과 같은 자료형의 Spring Bean이 2개 이상 존재할 경우 필드에 저장될 Spring Bean의 식별자(beanName)를 필드명과 같은 이름으로 변경 (DAO클래스에서 작성)
    • @Repository("studentDAO")
    • @Autowired 어노테이션은 필드의 자료형과 같은 자료형의 Spring Bean이 2개 이상 존재하는 경우 bean 엘리먼트에서 autowire 속성값을 [byName]으로 설정한 것과 같은 방법으로 의존성 주입
  • 해결법2) 필드의 자료형과 같은 자료형의 Spring Bean이 2개 이상 존재할 경우 필드에 저장될 Spring Bean에 대한 클래스에 @Primary 어노테이션을 사용하여 작성 (DAO클래스에서 작성)
  • 해결법3) 필드에 @Qualifier 어노테이션을 사용하여 의존성 주입을 위한 Spring Bean 지정 (service class에서 작성)
    • @Primary 어노테이션과 @Qualifier 어노테이션이 같이 설정된 경우 @Qualifier 어노테이션으로 의존성 주입
    • @Qualifier : 필드와 의존관계가 설정될 Spring Bean를 직접 지정하기 위한 어노테이션
    • @Autowired 어노테이션에 종속된 어노테이션
    • value 속성 : 의존성 주입을 위한 Spring Bean의 식별자(beanName)를 속성값으로 설정
    • 다른 속성이 없는 경우 속성값만 설정 가능 (beanName은 클래스이름에서 첫문자만 소문자로 변경)
    • @Qualifier("annotationStudentJdbcDAO")
    • 문제점 : 순환 참조(서로 참조)로 인해 메모리가 과도하게 쌓여 stackoverflow 현상이 일어남
  • @Autowired 어노테이션 대신 @Resource 어노테이션 또는 @Inject 어노테이션을 사용하여 의존성 주입 가능
    • @Autowired 어노테이션은 Spring Framework의 라이브러리로 제공하는 어노테이션이지만 @Resource 어노테이션 또는 @Inject 어노테이션은 JDK 라이브러리로 제공하는 어노테이션
    • @Resource 어노테이션 또는 @Inject 어노테이션은 다른 Framework에서 사용 가능
    • @Resource : bean 엘리먼트에서 autowire 속성값을 [byName]으로 설정한 것과 같은 방법으로 의존성 주입
    • @Inject : bean 엘리먼트에서 autowire 속성값을 [byType]으로 설정한 것과 같은 방법으로 의존성 주입


package xyz.itwill05.di;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

//@Component("studentService")

//@Service : Service 클래스를 스프링 컨테이너가 관리할 수 있는 Spring Bean으로 등록하기 위한 어노테이션
// => 클래스의 이름을 beanName으로 자동 설정하지만 value 속성으로 beanName 변경 가능
@Service("studentService")
public class AnnotationStudentServiceImpl implements StudentService {
	//@Autowired : 스프링 컨테이너로부터 Spring Bean를 제공받아 필드에 저장되도록 의존관계를 
	//자동으로 구현하기 위한 어노테이션
	// => 의존성 주입을 위해 필드에 사용하는 어노테이션 - 선언된 필드마다 어노테이션 설정 
	// => bean 엘리먼트에서 autowire 속성값을 [byType]으로 설정한 것과 같은 방법으로 의존성 주입 - Setter Injection
	// => Setter 메소드를 이용하여 의존관계를 설정하지만 Setter 메소드를 작성하지 않아도 의존성 주입
	//문제점)필드의 자료형과 같은 자료형의 Spring Bean이 2개 이상 존재할 경우 의존성 주입 실패 - NoUniqueBeanDefinitionException 발생
	//해결법-1)필드의 자료형과 같은 자료형의 Spring Bean이 2개 이상 존재할 경우 필드에 저장될
	//Spring Bean의 식별자(beanName)를 필드명과 같은 이름으로 변경
	// => @Autowired 어노테이션은 필드의 자료형과 같은 자료형의 Spring Bean이 2개 이상 존재하는
	//경우 bean 엘리먼트에서 autowire 속성값을 [byName]으로 설정한 것과 같은 방법으로 의존성 주입
	@Autowired
	//해결법-2)필드의 자료형과 같은 자료형의 Spring Bean이 2개 이상 존재할 경우 필드에 저장될
	//Spring Bean에 대한 클래스에 @Primary 어노테이션을 사용하여 작성
	//해결법-3)필드에 @Qualifier 어노테이션을 사용하여 의존성 주입을 위한 Spring Bean 지정
	// => @Primary 어노테이션과 @Qualifier 어노테이션이 같이 설정된 경우 @Qualifier 어노테이션으로 의존성 주입
	//@Qualifier : 필드와 의존관계가 설정될 Spring Bean를 직접 지정하기 위한 어노테이션
	// => @Autowired 어노테이션에 종속된 어노테이션
	//value 속성 : 의존성 주입을 위한 Spring Bean의 식별자(beanName)를 속성값으로 설정
	// => 다른 속성이 없는 경우 속성값만 설정 가능
	//@Qualifier("annotationStudentJdbcDAO")
	@Qualifier("anntationStudentMybatisDAO")
	private StudentDAO studentDAO;
	
	//@Autowired 어노테이션 대신 @Resource 어노테이션 또는 @Inject 어노테이션을 사용하여 의존성 주입 가능
	// => @Autowired 어노테이션은 Spring Framework의 라이브러리로 제공하는 어노테이션이지만  
	//@Resource 어노테이션 또는 @Inject 어노테이션은 JDK 라이브러리로 제공하는 어노테이션
	// => @Resource 어노테이션 또는 @Inject 어노테이션은 다른 Framework에서 사용 가능
	//@Resource : bean 엘리먼트에서 autowire 속성값을 [byName]으로 설정한 것과 같은 방법으로 의존성 주입
	//@Inject : bean 엘리먼트에서 autowire 속성값을 [byType]으로 설정한 것과 같은 방법으로 의존성 주입
	
	public AnnotationStudentServiceImpl() {
		System.out.println("### AnnotationStudentServiceImpl 클래스의 기본 생성자 호출 ###");
	}
	
	@Override
	public void addStudent(Student student) {
		System.out.println("*** AnnotationStudentServiceImpl 클래스 addStudent(Student student) 메소드 호출 ***");
		studentDAO.insertStudent(student);
	}

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

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

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

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




🐣 앱 실행

package xyz.itwill05.di;

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

public class AnnotationStudentApp {
	public static void main(String[] args) {
		System.out.println("================== Spring Container 초기화 전 ==================");
		ApplicationContext context=new ClassPathXmlApplicationContext("05-4_diAnnotation.xml");
		System.out.println("================== Spring Container 초기화 후 ==================");
		StudentService service=context.getBean("studentService",StudentService.class);
		service.addStudent(null);
		System.out.println("================================================================");
		((ClassPathXmlApplicationContext)context).close();		
	}
}






profile
Study Log 📂

0개의 댓글