[SPRING] 🧩 Dependency Injection

μž„λ‚™ν˜„Β·2022λ…„ 10μ›” 20일
0

SpringFramework

λͺ©λ‘ 보기
6/7
post-thumbnail

μ΄λ²ˆμ—λŠ” Dependency Injection(μ˜μ‘΄μ„± μ£Όμž…)에 κ΄€ν•˜μ—¬ ν¬μŠ€νŒ… ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.


1. πŸ’‰ DI

DIλŠ” Dependency Injection의 μ•½μžλ‘œ μš°λ¦¬λ§λ‘œλŠ” 'μ˜μ‘΄μ„± μ£Όμž…'이라고 λ²ˆμ—­ν•©λ‹ˆλ‹€.

이 단어λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„œλŠ” λ¨Όμ € dependency(의쑴)이 뭔지 μ•Œμ•„μ•Ό ν•©λ‹ˆλ‹€. μ—¬κΈ°μ„œ λ§ν•˜λŠ” dependencyλŠ” 객체 κ°„μ˜ μ˜μ‘΄μ„ μ˜λ―Έν•©λ‹ˆλ‹€.

λ¨Όμ € νšŒμ› κ°€μž…μ„ μ²˜λ¦¬ν•˜λŠ” κΈ°λŠ₯을 κ΅¬ν˜„ν•œ λ‹€μŒμ˜ μ½”λ“œλ₯Ό λ³΄κ² μŠ΅λ‹ˆλ‹€.

package spring;

import java.time.LocalDateTime;

public class MemberRegisterService {
	
	private MemberDao memberDao = new MemberDao();
	
	public void regist(RegisterRequest req) {
		// μ΄λ©”μΌλ‘œ νšŒμ› 데이터(Member) 쑰회
		Member member = memberDao.selectByEmail(req.getEmail());
		if(member != null) {
			// 같은 이메일을 가진 νšŒμ›μ΄ 이미 μ‘΄μž¬ν•˜λ©΄ μ˜ˆμ™Έ λ°œμƒ
			throw new DuplicateMemberException("dup email " + req.getEmail());
		}
		// 같은 이메일을 가진 νšŒμ›μ΄ μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ DB에 μ‚½μž…
		Member newMember = new Member(
			req.getEmail(), req.getPassword(), req.getName(),
			LocalDateTime.now());
		memberDao.insert(newMember);
	}
	
}

μœ„ μ½”λ“œλŠ” λ¨Όμ € λ™μΌν•œ 이메일을 가진 νšŒμ› 데이터가 μ‘΄μž¬ν•˜λŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€. λ§Œμ•½ 같은 이메일을 가진 νšŒμ› 데이터가 μ‘΄μž¬ν•˜λ©΄ μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ 같은 이메일을 가진 νšŒμ› 데이터가 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ νšŒμ› 정보λ₯Ό 담은 Member 객체λ₯Ό μƒμ„±ν•˜κ³  MemberDao 객체의 insert() λ©”μ„œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ DB에 νšŒμ› 데이터λ₯Ό μ‚½μž…ν•©λ‹ˆλ‹€.

μœ„ μ½”λ“œμ—μ„œ λˆˆμ—¬κ²¨λ³Ό 뢀뢄은 MemberRegisterService ν΄λž˜μŠ€κ°€ DB 처리λ₯Ό μœ„ν•΄ MemberDao 클래슀의 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

μ΄λ ‡κ²Œ ν•œ ν΄λž˜μŠ€κ°€ λ‹€λ₯Έ 클래슀의 λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•  λ•Œ 이λ₯Ό μ˜μ‘΄ν•œλ‹€κ³  ν‘œν˜„ν•©λ‹ˆλ‹€. μ•žμ˜ μ½”λ“œμ—μ„œλŠ” MemberRegisterService ν΄λž˜μŠ€κ°€ MemberDao ν΄λž˜μŠ€μ— μ˜μ‘΄ν•œλ‹€ κ³  ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • μ˜μ‘΄μ€ 변경에 μ˜ν•΄ 영ν–₯을 λ°›λŠ” 관계λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.

    예λ₯Όλ“€μ–΄ MemberDao의 insert() λ©”μ„œλ“œμ˜ 이름을 insertMember()둜 λ³€κ²½ν•˜λ©΄ 이 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” MemberRegisterService 클래슀의 μ†ŒμŠ€μ½”λ“œλ„ ν•¨κ»˜ λ³€κ²½λ©λ‹ˆλ‹€. μ΄λ ‡κ²Œ 변경에 λ”°λ₯Έ 영ν–₯이 μ „νŒŒλ˜λŠ” 관계λ₯Ό '의쑴'ν•œλ‹€κ³  ν‘œν˜„ν•©λ‹ˆλ‹€.

μ˜μ‘΄ν•˜λŠ” λŒ€μƒμ΄ 있으면 κ·Έ λŒ€μƒμ„ κ΅¬ν•˜λŠ” 방법이 ν•„μš”ν•©λ‹ˆλ‹€. κ°€μž₯ μ‰¬μš΄ 방법은 의쑴 λŒ€μƒ 객체λ₯Ό 직접 μƒμ„±ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

μ•žμ—μ„œ λ³Έ MemberRegisterService ν΄λž˜μŠ€λ„ λ‹€μŒ μ½”λ“œμ²˜λŸΌ 의쑴 λŒ€μƒμΈ MemberDao의 객체λ₯Ό 직접 μƒμ„±ν•΄μ„œ ν•„λ“œμ— ν• λ‹Ήν–ˆμŠ΅λ‹ˆλ‹€.

public class MemberRegisterService {
	// 의쑴 객체λ₯Ό 직접 생성
	private MemberDao memberDao = new MemberDao();
    ...

MemberRegisterService ν΄λž˜μŠ€μ—μ„œ μ˜μ‘΄ν•˜λŠ” MemberDao 객체λ₯Ό 직접 μƒμ„±ν•˜κΈ° λ•Œλ¬Έμ— MemberRegisterService 객체λ₯Ό μƒμ„±ν•˜λŠ” μˆœκ°„μ— MemberDao 객체도 ν•¨κ»˜ μƒμ„±λ©λ‹ˆλ‹€.

// μ˜μ‘΄ν•˜λŠ” MemberDao의 객체도 ν•¨κ»˜ 생성
MemberRegisterService svc = new MemberRegisterService();

μ΄λ ‡κ²Œ 클래슀 λ‚΄λΆ€μ—μ„œ 직접 의쑴 객체λ₯Ό μƒμ„±ν•˜λŠ” 것이 μ‰½μ§€λ§Œ μœ μ§€λ³΄μˆ˜ κ΄€μ μ—μ„œ λ¬Έμ œμ μ„ μœ λ°œν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ μ˜μ‘΄ν•˜λŠ” 객체λ₯Ό 직접 μƒμ„±ν•˜λŠ” 방식 외에 의쑴 객체λ₯Ό κ΅¬ν•˜λŠ” 또 λ‹€λ₯Έ 방법이 μžˆμŠ΅λ‹ˆλ‹€.

κ·Έ 방법은 DI와 μ„œλΉ„μŠ€ λ‘œμΌ€μ΄ν„°μž…λ‹ˆλ‹€. 이 쀑 Springκ³Ό κ΄€λ ¨λœ 것은 DIλ‘œμ„œ DIλ₯Ό μ΄μš©ν•΄μ„œ 의쑴 객체λ₯Ό κ΅¬ν•˜λŠ” 방법을 λ³΄κ² μŠ΅λ‹ˆλ‹€.



2. 🩺 DIλ₯Ό ν†΅ν•œ 의쑴 처리

DI(Dependency Injection, μ˜μ‘΄μ„± μ£Όμž…)λŠ” μ˜μ‘΄ν•˜λŠ” 객체λ₯Ό 직접 μƒμ„±ν•˜λŠ” λŒ€μ‹  의쑴 객체λ₯Ό μ „λ‹¬λ°›λŠ” 방식을 μ‚¬μš©ν•©λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄ μ•žμ„œ 의쑴 객체λ₯Ό 직접 μƒμ„±ν•œ MemberRegisterService ν΄λž˜μŠ€μ— DI방식을 μ μš©ν•˜λ©΄ μ•„λž˜ μ½”λ“œμ™€ 같이 κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

01.CHAP01/src/main/java/spring/MemberRegisterService.java

package spring;

import java.time.LocalDateTime;

public class MemberRegisterService {
	private MemberDao memberDao;
	
	public MemberRegisterService(MemberDao memberDao) {
		this.memberDao = memberDao;
	}
	
	public Long regist(RegisterRequest req) {
		Member member = memberDao.selectByEmail(req.getEmail());
		if(member != null) {
			throw new DuplicateMemberException("dup email " + req.getEmail());
		}
		Member newMember = new Member(
			req.getEmail(), req.getPassword(), req.getName(),
			LocalDateTime.now());
		memberDao.insert(newMember);
		return newMember.getId();
	}
	
}

μΆ”κ°€λœ 뢀뢄은 MemberRegisterService 클래슀의 μƒμ„±μž λΆ€λΆ„μž…λ‹ˆλ‹€

// μΆ”κ°€λœ λΆ€λΆ„
public MemberRegisterService(MemberDao memberDao) {
	this.memberDao = memberDao;
}

직접 의쑴 객체λ₯Ό μƒμ„±ν–ˆλ˜ μ½”λ“œμ™€ 달리 바뀐 μ½”λ“œλŠ” 의쑴 객체λ₯Ό 직접 μƒμ„±ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λŒ€μ‹  μœ„μ˜ // μΆ”κ°€λœ λΆ€λΆ„κ³Ό 같이 μƒμ„±μžλ₯Ό ν†΅ν•΄μ„œ 의쑴 객체λ₯Ό μ „λ‹¬λ°›μŠ΅λ‹ˆλ‹€.

즉 μƒμ„±μžλ₯Ό 톡해 MemberRegisterServiceκ°€ 의쑴(Dependency)ν•˜κ³  μžˆλŠ” MemberDao 객체λ₯Ό μ£Όμž…(Injection) 받은 κ²ƒμž…λ‹ˆλ‹€.

의쑴 객체λ₯Ό 직접 κ΅¬ν•˜μ§€ μ•Šκ³  μƒμ„±μžλ₯Ό ν†΅ν•΄μ„œ 전달받기 λ•Œλ¬Έμ— 이 μ½”λ“œλŠ” DI(μ˜μ‘΄μ„± μ£Όμž…) νŒ¨ν„΄μ„ λ”°λ₯΄κ³  μžˆμŠ΅λ‹ˆλ‹€.


DIλ₯Ό μ μš©ν•œ κ²°κ³Ό MemberRegisterService 클래슀λ₯Ό μ‚¬μš©ν•˜λŠ” μ½”λ“œλŠ” λ‹€μŒκ³Ό 같이 MemberRegisterService 객체λ₯Ό 생성할 λ•Œ μƒμ„±μžμ— MemberDao 객체λ₯Ό 전달해야 ν•©λ‹ˆλ‹€.

MemberDao dao = new MemberDao();
// 의쑴 객체λ₯Ό μƒμ„±μžλ₯Ό 톡해 μ£Όμž…ν•œλ‹€
MemberRegisterService svc = new MemberRegisterService(dao);



3. πŸŒ” DI와 의쑴 객체 λ³€κ²½μ˜ μœ μ—°ν•¨

의쑴 객체λ₯Ό 직접 μƒμ„±ν•˜λŠ” 방식은 ν•„λ“œλ‚˜ μƒμ„±μžμ—μ„œ new μ—°μ‚°μžλ₯Ό μ΄μš©ν•˜μ—¬ 객체λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. νšŒμ› 등둝 κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” MemberRegisterService ν΄λž˜μŠ€μ—μ„œ λ‹€μŒ μ½”λ“œμ²˜λŸΌ 의쑴 객체λ₯Ό 직접 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.

public class MemberRegisterService {
	private MemberDao memberDao = new MemberDao();
    ...
}

μ—¬κΈ°μ„œ νšŒμ›μ˜ μ•”ν˜Έ λ³€κ²½ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” ChangePasswordService ν΄λž˜μŠ€λ„ λ‹€μŒκ³Ό 같이 의쑴 객체λ₯Ό 직접 μƒμ„±ν•œλ‹€κ³  ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

public class ChangePasswordService {
	private MemberDao memberDao = new MemberDao();
    ...
}

MemberDao ν΄λž˜μŠ€λŠ” νšŒμ› 데이터λ₯Ό λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯ν•œλ‹€κ³  κ°€μ •ν•˜κ² μŠ΅λ‹ˆλ‹€. 이런 μƒν™©μ—μ„œ νšŒμ› λ°μ΄ν„°μ˜ λΉ λ₯Έ 쑰회λ₯Ό μœ„ν•΄ μΊμ‹œλ₯Ό μ μš©ν•΄μ•Ό ν•˜λŠ” 상황이 λ°œμƒν•˜μ˜€μŠ΅λ‹ˆλ‹€.

κ·Έλž˜μ„œ MemberDao 클래슀λ₯Ό 상속받은 CachedMemberDao 클래슀λ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

public class CachedMemberDao extends MemberDao {
	...
}

  • Cache(μΊμ‹œ)

    μΊμ‹œλŠ” 데이터 값을 볡사해 λ†“λŠ” μž„μ‹œ μž₯μ†Œ λ₯Ό κ°€λ¦¬ν‚΅λ‹ˆλ‹€. 보톡 쑰회 속도 ν–₯상을 μœ„ν•΄ μΊμ‹œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. DB에 μžˆλŠ” 데이터 쀑 자주 μ‘°νšŒν•˜λŠ” 데이터λ₯Ό λ©”λͺ¨λ¦¬λ₯Ό μ‚¬μš©ν•˜λŠ” μΊμ‹œμ— λ³΄κ΄€ν•˜λ©΄ 쑰회 속도λ₯Ό ν–₯μƒμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

μΊμ‹œ κΈ°λŠ₯을 μ μš©ν•œ CachedMemberDaoλ₯Ό μ‚¬μš©ν•˜λ €λ©΄ MemberRegisterService ν΄λž˜μŠ€μ™€ ChangePasswordService 클래슀의 μ½”λ“œλ₯Ό μ•„λž˜μ™€ 같이 λ³€κ²½ν•΄ μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

public class MemberRegisterService {
	private MemberDao memberDao = new CachedMemberDao();
    ...
}

public class ChangePasswordService {
	private MemberDao memberDao = new CachedMemberDao();
    ...
}

λ§Œμ•½ MemberDao 객체가 ν•„μš”ν•œ ν΄λž˜μŠ€κ°€ 100개면 100개의 클래슀 λͺ¨λ‘, 10000개면 10000개의 클래슀 λͺ¨λ‘ λ™μΌν•˜κ²Œ μ†ŒμŠ€ μ½”λ“œλ₯Ό λ³€κ²½ν•΄μ•Ό ν•©λ‹ˆλ‹€.


λ™μΌν•œ μƒν™©μ—μ„œ DIλ₯Ό μ‚¬μš©ν•˜λ©΄ μˆ˜μ •ν•  μ½”λ“œκ°€ μ€„μ–΄λ“€κ²Œ λ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ λ‹€μŒκ³Ό 같이 μƒμ„±μžλ₯Ό ν†΅ν•΄μ„œ 의쑴 객체λ₯Ό μ£Όμž… 받도둝 κ΅¬ν˜„ν–ˆλ‹€κ³  ν•˜κ² μŠ΅λ‹ˆλ‹€.

public class MemberRegisterService {
	private MemberDao memberDao;
	public MemberRegisterService(MemberDao memberDao) {
		this.memberDao = memberDao;
	}
    ...
}

public class ChangePasswordService {
	private MemberDao memberDao;
	public ChangePasswordService(MemberDao memberDao) {
		this.memberDao = memberDao;
	}
    ...
}

μ΄λ•Œ 두 클래슀의 객체λ₯Ό μƒμ„±ν•˜λŠ” μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

MemberDao memberDao = new MemberDao();
MemberRegisterService regSvc = new MemberRegisterService(memberDao);
ChangePasswordService pwdSvc = new ChangePasswordService(memberDao);

이제 MemberDao λŒ€μ‹  CachedMemberDaoλ₯Ό μ‚¬μš©ν•˜λ„λ‘ μˆ˜μ •ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. μˆ˜μ •ν•΄μ•Ό ν•  μ†ŒμŠ€ μ½”λ“œλŠ” ν•œ κ³³(!)λΏμž…λ‹ˆλ‹€. μ•„λž˜ μ½”λ“œμ²˜λŸΌ MemberDao 객체λ₯Ό μƒμ„±ν•˜λŠ” μ½”λ“œλ§Œ λ³€κ²½ν•˜λ©΄ λ©λ‹ˆλ‹€.

MemberDao memberDao = new CachedMemberDao();
MemberRegisterService regSvc = new MemberRegisterService(memberDao);
ChangePasswordService pwdSvc = new ChangePasswordService(memberDao);

DIλ₯Ό μ‚¬μš©ν•˜λ©΄ MemberDao 객체λ₯Ό μ‚¬μš©ν•˜λŠ” ν΄λž˜μŠ€κ°€ μˆ˜μ‹­κ°œμ—¬λ„ λ³€κ²½ν•  곳은 의쑴 μ£Όμž… λŒ€μƒμ΄ λ˜λŠ” 객체λ₯Ό μƒμ„±ν•˜λŠ” μ½”λ“œ ν•œ κ³³ λΏμž…λ‹ˆλ‹€. μ•žμ„œ 의쑴 객체λ₯Ό 직접 μƒμ„±ν–ˆλ˜ 방식에 λΉ„ν•΄ λ³€κ²½ν•  μ½”λ“œκ°€ ν•œ 곳으둜 μ§‘μ€‘λ˜λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.


이번 ν¬μŠ€νŒ…μ—μ„œλŠ” Dependency Injection에 κ΄€ν•˜μ—¬ μ˜ˆμ‹œλ₯Ό 보며 곡뢀λ₯Ό ν•΄ λ³΄μ•˜μŠ΅λ‹ˆλ‹€.

λ‹€μŒ ν¬μŠ€νŒ…μ—μ„œλŠ” 예제 ν”„λ‘œμ νŠΈλ₯Ό λ§Œλ“€μ–΄μ„œ 곡뢀λ₯Ό ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

κ°μ‚¬ν•©λ‹ˆλ‹€.


πŸ’‘ Reference

https://www.kame.co.kr/nkm/detail.php?tcode=306&tbook_jong=3

profile
μ½”λ”©ν•˜λŠ” μˆ˜ν•™κ³Ό

0개의 λŒ“κΈ€