환경
윈도우즈 10 / 이클립스 2022-06 (4.24.0) / Java SE 18 / 메이븐 3.8.6 / spring-context 5.3.22
교재
책 : 초보 웹 개발자를 위한 스프링5 프로그래밍 입문
영상 : 예제로 배우는 스프링 입문(개정판)
변경에 의해 영향이 전파되는 관계
e.g. 한 클래스가 다른 클래스의 메소드를 호출
아래 코드에서 Gorani는 GoraniAction에 의존
( = Gorani는 GoraniAction이 있어야만 동작 )
GoraniAction의 메소드를 호출GoraniAction의 변경에 영향 받음Gorani는 의존대상 객체를 클래스 내에서 직접 생성하여 의존 객체를 구함
이 방법은 프로그램의 유연성과 유지보수성을 낮추는 등의 문제를 가짐
class GoraniAction {
public void cry(String s) { System.out.println("Gorani cry \"" + s + "\""); }
public void sleep() { System.out.println("Gorani sleeps.."); }
}
class Gorani {
private String crySound;
private GoraniAction action = new GoraniAction();
public Gorani(String crySound) { this.crySound = crySound; }
public void cry() { action.cry(crySound); }
public void sleep() { action.sleep(); }
}
public class Main {
public static void main(String[] args) {
Gorani gorani = new Gorani("quaaak!");
gorani.cry(); // Gorani cry "quaaak!"
gorani.sleep(); // Gorani sleeps..
}
}
참고 의존성이란
어떤 클래스 내에서 의존하는 클래스를 직접 생성하는 대신 외부로부터 의존객체를 주입받는 것
아래 코드는 Gorani가 의존객체인 GoraniAction객체를 직접 생성
class GoraniAction {
public void cry(String s) { System.out.println(s); }
}
class Gorani {
private GoraniAction action = new GoraniAction();
public void cry() { action.cry("quaaak"); }
}
public class Main {
public static void main(String[] args) {
Gorani gorani = new Gorani();
gorani.cry();
}
}
아래 코드는 Gorani가 외부로부터 GoraniAction객체를 주입받음
class GoraniAction {
public void cry(String s) { System.out.println(s); }
}
// ---------------------
// 방법 1. 생성자를 통한 의존 주입
class Gorani {
private GoraniAction action;
public Gorani(GoraniAction action) { this.action = action; }
public void cry() { action.cry("quaaak"); }
}
public class Main {
public static void main(String[] args) {
Gorani gorani = new Gorani(new GoraniAction());
gorani.cry();
}
}
// ---------------------
// 방법 2. setter를 통한 의존 주입
class Gorani {
private GoraniAction action;
public void cry() { action.cry("quaaak"); }
public void setAction(GoraniAction action) { this.action = action; }
}
public class Main {
public static void main(String[] args) {
Gorani gorani = new Gorani();
gorani.setAction(new GoraniAction());
gorani.cry();
}
}
Assembler.javaAppCtx.java고라니 주인은 고라니 관리 객체를 통해 고라니를 구매/판매
구매한 고라니는 고라니 관리 객체의 해시맵에 put()
판매한 고라니는 고라니 관리 객체의 해시맵에서 remove()
모두 같은 패키지라고 가정
// Main.java
public class Main {
public static void main(String[] args) {
Assembler assembler = new Assembler();
GoraniOwner owner = assembler.getGoraniOwner();
owner.buyGorani(1, "wonjin");
owner.buyGorani(2, "martindog");
owner.buyGorani(3, "comgong");
owner.callGorani(2); // ID : 2, NAME : martindog
owner.callGorani(53); // Gorani Not Found
owner.callAllGoranis();
// ID : 1, NAME : wonjin
// ID : 2, NAME : martindog
// ID : 3, NAME : comgong
owner.sellGorani(3);
owner.sellGorani(5353); // ID 5353 : Not Found
owner.sellGorani(1);
owner.callAllGoranis(); // ID : 2, NAME : martindog
}
}
// Assembler.java
public class Assembler {
private GoraniDao goraniDao = new GoraniDao();
private GoraniOwner goraniOwner = new GoraniOwner();
private GoraniCaller goraniCaller = new GoraniCaller();
// 생성자 방식 DI
private AllGoranisCaller allGoranisCaller = new AllGoranisCaller(goraniCaller, goraniDao);
public Assembler() {
// Setter 방식 DI
goraniOwner.setGoraniDao(goraniDao);
goraniOwner.setGoraniCaller(goraniCaller);
goraniOwner.setAllGoranisCaller(allGoranisCaller);
}
public GoraniOwner getGoraniOwner() {
return goraniOwner;
}
}
// Gorani.java
public class Gorani {
private int id;
private String name;
public Gorani(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
// GoraniDao.java
import java.util.Collection;
import java.util.HashMap;
public class GoraniDao {
private HashMap<Integer, Gorani> list = new HashMap<Integer, Gorani>(); // Database
public Gorani getGoraniById(int id) {
return list.get(id);
}
public Collection<Gorani> getAllGoranis() {
return list.values();
}
public void add(Gorani gorani) {
boolean isExist = getGoraniById(gorani.getId()) != null;
if(isExist)
throw new RuntimeException("ID : " + gorani.getId() + " : Already Exist");
list.put(gorani.getId(), gorani);
}
public void remove(int id) {
Gorani gorani = getGoraniById(id);
if(gorani == null)
throw new RuntimeException("ID " + id + " : Not Found");
list.remove(id);
}
}
// GoraniOwner.java
public class GoraniOwner {
private GoraniDao goraniDao;
private GoraniCaller goraniCaller;
private AllGoranisCaller allGoranisCaller;
// setter방식의 DI
public void setGoraniDao(GoraniDao goraniDao) { this.goraniDao = goraniDao; }
public void setGoraniCaller(GoraniCaller goraniCaller) { this.goraniCaller = goraniCaller; }
public void setAllGoranisCaller(AllGoranisCaller allGoranisCaller) { this.allGoranisCaller = allGoranisCaller; }
public void buyGorani(int id, String name) {
Gorani obj = new Gorani(id, name);
goraniDao.add(obj);
}
public void sellGorani(int id) {
try { goraniDao.remove(id); }
catch( Exception e ) { System.out.println(e.getMessage()); }
}
public void callGorani(int id) {
Gorani obj = goraniDao.getGoraniById(id);
try { goraniCaller.call(obj); }
catch( Exception e ) { System.out.println(e.getMessage()); }
}
public void callAllGoranis() {
allGoranisCaller.call();
}
}
// GoraniCaller.java
public class GoraniCaller {
public void call(Gorani gorani) {
if(gorani == null)
throw new RuntimeException("Gorani Not Found");
System.out.println("ID : " + gorani.getId() + ", NAME : " + gorani.getName());
}
}
// AllGoranisCaller.java
import java.util.Collection;
import java.util.Iterator;
public class AllGoranisCaller {
private GoraniCaller caller;
private GoraniDao goraniDao;
// 생성자 방식의 DI
public AllGoranisCaller(GoraniCaller caller, GoraniDao goraniDao) {
this.caller = caller;
this.goraniDao = goraniDao;
}
public void call() {
Collection<Gorani> list = goraniDao.getAllGoranis();
Iterator<Gorani> itr = list.iterator();
while(itr.hasNext())
caller.call(itr.next());
}
}
위 코드에서
// Main.jva
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static ApplicationContext ctx;
public static void main(String[] args) {
ctx = new AnnotationConfigApplicationContext(AppCtx.class);
GoraniOwner owner = ctx.getBean("goraniOwner", GoraniOwner.class);
owner.buyGorani(1, "wonjin");
owner.buyGorani(2, "martindog");
owner.buyGorani(3, "comgong");
owner.callGorani(2); // ID : 2, NAME : martindog
owner.callGorani(53); // Gorani Not Found
owner.callAllGoranis();
// ID : 1, NAME : wonjin
// ID : 2, NAME : martindog
// ID : 3, NAME : comgong
owner.sellGorani(3);
owner.sellGorani(5353); // ID 5353 : Not Found
owner.sellGorani(1);
owner.callAllGoranis(); // ID : 2, NAME : martindog
}
}
// AppCtx.java
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
@Configuration
public class AppCtx {
@Bean
public GoraniDao goraniDao() {
return new GoraniDao();
}
@Bean
public GoraniCaller goraniCaller() {
return new GoraniCaller();
}
@Bean
public AllGoranisCaller allGoranisCaller() {
return new AllGoranisCaller(goraniCaller(), goraniDao());
}
@Bean
public GoraniOwner goraniOwner() {
GoraniOwner owner = new GoraniOwner();
owner.setGoraniDao(goraniDao());
owner.setGoraniCaller(goraniCaller());
owner.setAllGoranisCaller(allGoranisCaller());
return owner;
}
}
참고