스프링 DI
의존이란?
- DI는 의존 주입이다.
- 의존 : 객체 간의 의존을 의미
- MemberRegisterService에서 MemberDao 클래스의 메서드를 사용
- 한 클래스가 다른 클래스의 메서드를 실행할 때 이를 의존한다라고 표현
- 의존은 변경에 의해 영향을 받는 관계를 의미
- 의존하는 대상을 구하는 방법은 의존 대상 객체를 직접 생성하는것
private MemberDao memberDao = new MemberDao();
- 클래스 내부에서 직접 의존 객체를 생성하는 것이 쉽긴 하지만 유지보수 관점에서 좋지 않음 따라서 DI를 이용해서 의존 객체를 구함
package chap02;
public class MemberRegisterService {
private MemberDao memberDao = new MemberDao();
public void regist(RegisterRequest req) {
Member member = memberDao.selectByEmail(req.getEmail());
if(member != null) {
throw new DuplicateMemberException("에러");
}
Member newMember = new Member();
memberDao.insert();
}
}
DI를 통한 의존 처리
- DI는 의존하는 객체를 직접 생성하는 대신 의존 객체를 전달받는 방식을 사용
- DI를 사용하면 변경의 유연함이 생긴다.
package spring;
public class MemberRegisterService {
public MemberDao memberDao;
public MemberRegisterService(MemberDao memberDao) {
this.memberDao = memberDao;
}
public void regist(RegisterRequest req) {
Member member = memberDao.selectByEmail(req.getEmail());
if(member != null) {
throw new DuplicateMemberException("에러");
}
Member newMember = new Member();
memberDao.insert();
}
}
예제 프로젝트
회원 데이터 관련 클래스
package com.jisung.spring;
import java.time.LocalDateTime;
public class Member {
private Long id;
private String email;
private String password;
private String name;
private LocalDateTime registerDateTime;
public Member(String email, String password, String name, LocalDateTime registerDateTime) {
this.email = email;
this.password = password;
this.name = name;
this.registerDateTime = registerDateTime;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
public String getName() {
return name;
}
public LocalDateTime getRegisterDateTime() {
return registerDateTime;
}
public void changePassword(String oldPassword, String newPassword) {
if(!password.equals(oldPassword)) {
throw new WrongIdPasswordException();
}
this.password = newPassword;
}
}
package com.jisung.spring;
public class WrongIdPasswordException extends RuntimeException{
}
package com.jisung.spring;
import java.util.HashMap;
import java.util.Map;
public class MemberDao {
private static long nextId = 0;
private Map<String, Member> map = new HashMap<String, Member>();
public Member selectByEmail(String email) {
return map.get(email);
}
public void insert(Member member) {
member.setId(++nextId);
map.put(member.getEmail(),member);
}
public void update(Member member) {
map.put(member.getEmail(), member);
}
}
회원 가입 처리 관련 클래스
package com.jisung.spring;
public class DuplicateMemberException extends RuntimeException{
public DuplicateMemberException(String message) {
super(message);
}
}
package com.jisung.spring;
public class RegisterRequest {
private String email;
private String password;
private String confirmPassword;
private String name;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isPasswordEqualToConfirmPassword() {
return password.equals(confirmPassword);
}
}
package com.jisung.spring;
import java.time.LocalDateTime;
public class MemberRegisterService {
public 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();
}
}
암호변경 관련 클래스
package com.jisung.spring;
public class ChangePasswordService {
private MemberDao memberDao;
public void changePassword(String email,String oldPwd, String newPwd) {
Member member = memberDao.selectByEmail(email);
if(member == null) {
throw new MemberNotFoundException();
}
member.changePassword(oldPwd, newPwd);
memberDao.update(member);
}
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
}
package com.jisung.spring;
public class MemberNotFoundException extends RuntimeException {
}
객체 조립기
- 메인 메서드에서 객체를 주입하는것도 괜찮은 방법
- 메인 메서드에서 객체를 주입하지 않고 객체를 주입해주는 클래스를 따로 작성
package assembler;
import com.jisung.spring.ChangePasswordService;
import com.jisung.spring.MemberDao;
import com.jisung.spring.MemberRegisterService;
public class Assembler {
private MemberDao memberDao;
private MemberRegisterService regSvc;
private ChangePasswordService pwdSvc;
public Assembler() {
memberDao = new MemberDao();
regSvc = new MemberRegisterService(memberDao);
pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao);
}
public MemberDao getMemberDao() {
return memberDao;
}
public MemberRegisterService getRegSvc() {
return regSvc;
}
public ChangePasswordService getPwdSvc() {
return pwdSvc;
}
}
조립기 사용예제
package main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.jisung.spring.ChangePasswordService;
import com.jisung.spring.DuplicateMemberException;
import com.jisung.spring.MemberNotFoundException;
import com.jisung.spring.MemberRegisterService;
import com.jisung.spring.RegisterRequest;
import com.jisung.spring.WrongIdPasswordException;
import assembler.Assembler;
public class MainForAssembler {
private static Assembler assembler = new Assembler();
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while(true) {
System.out.println("명령어를 입력하세요 ");
String command = reader.readLine();
if(command.equalsIgnoreCase("exit")) {
System.out.println("종료합니다.");
break;
}
if(command.startsWith("new ")) {
processNewCommand(command.split(" "));
continue;
}
if(command.startsWith("change ")) {
processChangeCommand(command.split(" "));
continue;
}
printHelp();
}
}
private static void processNewCommand(String[] arg) {
if(arg.length != 5) {
printHelp();
return;
}
MemberRegisterService regSvc = assembler.getRegSvc();
RegisterRequest req = new RegisterRequest();
req.setEmail(arg[1]);
req.setName(arg[2]);
req.setPassword(arg[3]);
req.setConfirmPassword(arg[4]);
if(!req.isPasswordEqualToConfirmPassword()) {
System.out.println("일치하지 않음");
return;
}
try {
regSvc.regist(req);
System.out.println("등록했습니다.");
} catch (DuplicateMemberException e) {
System.out.println("이미 존재하는 이메일 입니다.");
}
}
private static void processChangeCommand(String[] arg) {
if(arg.length != 4) {
printHelp();
return;
}
ChangePasswordService changePwdSvc = assembler.getPwdSvc();
try {
changePwdSvc.changePassword(arg[1], arg[2], arg[3]);
System.out.println("암호 변경완료");
} catch (MemberNotFoundException e) {
System.out.println("존재하지 않은 이메일입니다.");
} catch (WrongIdPasswordException e) {
System.out.println("이메일과 암호가 일치하지 않습니다.");
}
}
private static void printHelp() {
System.out.println("잘못된 명령입니다!");
}
}