스프링 DI

HeeSeong·2021년 7월 24일
0
post-thumbnail

스프링 DI


DI는 "Dependency Injection"의 약자로 '의존 주입'이다.

package spring;

import java.time.LocalDateTime;

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

	public Long 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);
		return newMember.getId();
	}
}

서로 다른 회원은 동일한 이메일 주소를 사용할 수 없다는 요구사항이 있다고 가정한다. MemberRegisterService 클래스는 MemberDao 객체의 selectByEmail() 메서드를 이용해서 동일한 이메일을 가진 회원 데이터가 존재하는지 확인한다.

눈여겨볼 점은 MemberRegisterService 클래스가 DB 처리를 위해 MemberDao 클래스의 메서드를 사용한다는 것이다. 이렇게 한 클래스가 다른 클래스의 메서드를 실행할 때 이를 '의존'한다고 표현한다.

의존하는 대상이 있으면 그 대상을 구하는 방법이 필요하다. 클래스 내부에서 직접 의존 객체를 생성하는 것이 쉽긴 하지만 유지보수 관점에서 문제점을 유발할 수 있다.


DI를 통한 의존처리


DI는 의존하는 객체를 직접 생성하는 대신 의존 객체를 전달받는 방식을 사용한다.


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

위의 코드는 의존 객체를 직접 생성하지 않는다. 대신 생성자를 통해서 의존 객체를 전달받는다.
그냥 직접 의존 객체를 생성하면 되는데 왜 굳이 생성자를 통해서 의존하는 객체를 주입하는 것일까?
기본적인 이유는 '변경의 유연함'이다.


DI와 의존 객체 변경의 유연함


MemberDao 클래스는 회원 데이터를 DB에 저장한다. 이 상태에서 회원 데이터의 빠른 조회를 위해 캐시를 적용해야 하는 상황이 발생했다. 그래서 MemberDao 클래스를 상속 받은 CachedMemberDao 클래스를 만들었다.

캐시 기능을 적용한 CachedMemberDao를 사용하려면 MemberRegisterService 클래스와 ChangePasswordService 클래스의 코드를 이렇게 변경해야 한다.



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

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


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

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

동일한 상황에서 DI를 사용하면 수정할 코드가 줄어든다. 두 클래스의 객체를 생성하는 코드는 다음과 같다.


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

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

MemberDao memberDao = new CachedMemberDao(); // 이 부분
MemberRegisterService regSvc = new MemberRegisterService(memberDao;
ChangePasswordService pwdSvc = new changePasswordService(memberDao);

수정해야 할 소스 코드는 한 곳뿐이다. MemberDao 객체를 생성하는 코드만 변경하면 된다. 의존 객체를 직접 생성했던 방식에 비해 변경할 코드가 한 곳으로 집중되는 것을 알 수 있다.


profile
끊임없이 성장하고 싶은 개발자

0개의 댓글

관련 채용 정보