이 글에서는 xml, 어노테이션 등을 다루는 법은 안적었습니다.
스프링을 들어가기전에 복습하는 차원에서 꼭 알아야 할 기본 개념을 짚고 넘어가자.
스프링에서는 기본적으로 DI(의존성 주입)을 제공하는데 이 글은 그것이 왜 사용이 되는지에 대한 글이다.
아주 쉽게 이해를 돕기 위해 임의로 국어점수와 영어점수를 더하고(plusLogic)
그 결과값 받아 출력하는 로직(printLogic)을 따로 짜보겠다.
public interface plus {
int plusResult();
}
public class plusLogic implements plus{
private int kor = 30;
private int eng = 40;
@Override
public int plusResult() {
return kor+eng;
}
}
국어점수와 영어점수를 더하는 로직
public interface print {
void printActionLogic();
}
public class printLogic implements print{
private plus pluslogic;
printLogic() {
pluslogic = new plusLogic();
}
@Override
public void printActionLogic() {
System.out.printf("plusResult : %d", pluslogic.plusResult());
}
}
plusLogic으로 부터 값을 받아 그 결과를 출력하는 로직
이 두 로직을 보면 'printLogic'에서 'plusLogic'객체를 생성하여 사용하고 있다.
즉 두 클래스는 아주 강하게 결합되어 있다고 볼 수 있다.
그렇다면 이 로직은 어떻게 실행할까?
public class mainLogic {
public static void main(String[] args) {
print printlogic = new printLogic();
printlogic.printActionLogic();
}
}
출력결과 // plusResult : 70
콘솔창에 띄워주는 로직
이 로직을 보면 'plusLogic'은 'printLogic'안에 담겨져 있기 때문에 'mainLogic'에서는 보이지도 않는다.
??? : "혹시 출력결과를 한글로 '결과 : '이렇게 바꿔주실 수 있나요?"
만약에 로직이 복잡하게 구현된 10000줄짜리면 어떡할건가?
일일이 다 수정해야 할수도 있는 끔찍한 상황일 것이다.
또한 결합되어 있는 다른 클래스들도 다 뜯어봐야 할수도 있다.
울며겨자 먹기로 한글로 출력하는 로직을 새로 구성해보자.
public class koreaPrintLogic implements print {
private plus pluslogic;
koreaPrintLogic(){
pluslogic = new plusLogic();
}
@Override
public void printActionLogic() {
System.out.printf("결과 : %d", pluslogic.plusResult());
}
}
출력결과 // 결과 : 70
결과를 한글로 출력해주는 로직
동일한 방법으로 새로운 한글로 출력하는 로직을 새로 구성했다.
근데 만약에 'mainLogic'을 수정할 일이 생기고 강한 결합때문에 차례대로 'koreaPrintLogic', 'plusLogic'을 수정해야 한다고 가정하자. 그리고 그 수정해야 하는 줄이 10000줄이라고 생각하자.
우여곡절 끝에 수정을 성공했다고 하자.
그런데 어느날...
??? : "혹시 저번 때처럼 'plusResult :' 로 출력해주실 수 있나요?"
(날 죽여줘..)
만약에 저 로직들이 10000줄로 구성되어있다면 다시 로직을 짜는게 빠를 것이다.
왜냐하면 이미 'plusLogic'은 'koreaPrintLogic'에 맞게 수정되었기 때문이다.
그렇다면 각 클래스 마다 결합력을 낮춰서 부품처럼 사용하는 방법은 없을까?
가능하다!
public class printLogic implements print{
private plus pluslogic;
/*
printLogic() {
pluslogic = new plusLogic();
}
*/
printLogic(plus pluslogic) {
this.pluslogic = pluslogic;
}
public void printActionLogic() {
System.out.printf("plusResult : %d", pluslogic.plusResult());
}
}
-------------------------------------------------------------------------------------
public class koreaPrintLogic implements print {
private plus pluslogic;
/*
koreaPrintLogic() {
pluslogic = new plusLogic();
}
*/
public koreaPrintLogic(plus pluslogic){
this.pluslogic = pluslogic;
}
@Override
public void printActionLogic() {
System.out.printf("결과 : %d", pluslogic.plusResult());
}
}
수정한 출력 로직
public class mainLogic {
public static void main(String[] args) {
plus pluslogic = new plusLogic();
print printlogic = new printLogic(pluslogic);
print koreaprintlogic = new koreaPrintLogic(pluslogic);
printlogic.printActionLogic();
System.out.println();
koreaprintlogic.printActionLogic();
}
//출력결과
plusResult : 70
결과 : 70
이렇게 되면 원하는 대로 객체를 생성하여 출력이 가능해진다.
클래스들 사이의 결합이 느슨해 짐에 따라 자유롭게 변경이 가능하다.
그리고 각자 고유의 캡슐화 된 클래스이므로 유지보수가 용이하다.(물론 이 예제에서는 각 클래스마다 물고 늘어지는 로직을 구현하지 않았다.)
근데 스프링에서는 이렇게 객체를 생성하고 소멸, 의존관계를 개발자가 직접하는 것이 아닌 XML이나 어노테이션을 통해 스프링 프레임워크가 도와준다. 그것을 DI라 한다.