IoC(Inversion of Control/제어의 역전)라고도 하는 DI(Dependency Injection/의존성 주입)
의사코드 | 자바 표현 |
---|---|
디자니어가 옷을 생산한다. 옷은 내부적으로 단추를 생산한다. | new Clothes(); Clothes 객체 생성자에서 new Button(); |
(⬆️ 문장이 어색함 -> 현실과 맞지 않음)
의존성을 단순하게 정의하면 new
new를 실행하는 Clothes가 Button에 의존
➡️ 전체가 부분에 의존 / 프로그래밍에서 의존 관계는 new로 표현
주입이란 말은 외부에서라는 뜻을 내포
의사코드 | 자바 표현 - 생성자 인자 이용 |
---|---|
디자니어가 옷을 생산한다. 디자이너가 옷을 생산하면서 단추를 부착한다. | Button button = new WoodButton(); Clothes clothes = new Clothes(button); |
package 의존성주입1
public interface Button {
String getMaterial();
}
package 의존성주입1
//전략
public class WoodButton implements Button {
public String getMaterial() {
return "나무 단추";
}
}
package 의존성주입1
//전략
public class PlasticButton implements Button {
public String getMaterial() {
return "플라스틱 단추";
}
}
package 의존성주입1
public class Clothes {
Button button;
// 생성자에 parameter 추가
public Clothes(Button button) {
this.button=button;
}
// 컨텍스트
public String getMaterial() {
return button.getMaterial();
}
}
package 의존성주입1
public class 메인 {
//클라이언트
public static void main(String[] args) {
Button button = new WoodButton();
Clothes clothes = new Clothes(button);
System.out.println(clothes.getMaterial());
}
}
new를 사용해 단추를 생산하는 부분을 Clothes.java에서가 아닌 메인.java에서 수행
생성된 button 객체 참조 변수를 Clothes 생성자의 인자로 전달
Clothes가 Button을 생산하는 것은 현실과 맞지 않음
Clothes는 Button 인터페이스를 구현한 어떤 객체가 들어오기만 하면 정상적으로 작동함
현실 세계의 표준 규격 준수 = 프로그래밍 세계의 인터페이스 구현
의사코드 | 자바 표현 - 속성 접근자 메서드 사용 |
---|---|
디자니어가 옷을 생산한다. 디자이너가 단추를 생산한다. 디자이너가 옷에 단추를 부착한다. | Button button = new WoodButton(); Clothes clothes = new Clothes(); clothes.setButton(button) |
package 의존성주입2
public class Clothes {
Button button;
public Button getButton() {
return button;
}
public void setButton(Button button) {
this.button = button;
}
public String getMaterial() {
return button.getMaterial();
}
}
Clothes.java는 생성자가 사라졌고, button 속성에 대한 접근자(getter), 설정자(setter) 메서드가 생겼다.
package 의존성주입2
public class 메인 {
//클라이언트
public static void main(String[] args) {
Button button = new WoodButton();
Clothes clothes = new Clothes();
button.setButton(button);
System.out.println(clothes.getMaterial());
}
}
Clothes.java의 수정에 따라 메인.java도 위와 같이 변경한다.
재컴파일/재배포하지 않아도 XML파일만 수정하면 프로그램의 실행 결과를 바꿀 수 있음
자바에서 접근자 및 설정자 메서드를 속성 메서드라고 하는데 영어로 속성은 Property이다.
속성 메서드를 XML파일의 property 태그를 이용하여 대체하는 것
더욱 현실적인 내용을 반영하기에 이해하기 쉽고 유지보수하기 쉬움
Button button
public void setButton(Button button) {
this.button = button
}
⬆️ 위의 코드를 @Autowired 어노테이션을 활용하면 아래와 같이 수정할 수 있다.
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
Button button;
설정자 메서드를 이용하지 않고도 스프링 프레임워크가 설정 파일을 통해 설정자 메서드 대신 속성을 주입해 준다.
(스프링 설정 파일 코드는 생략)
@Autowired -> @Resource로 변경
@Autowired는 스프링의 어노테이션, type의 매칭 우선순위가 id보다 높음
@Resource는 자바의 표준 어노테이션, type의 매칭 우선순위가 id보다 낮음
@Resource의 경우 id로 매칭할 빈을 찾지 못하면 type으로 매칭할 빈을 찾음
스프링 DI가 의존성(new)에 대한 주입이라면
스프링 AOP는 로직(code) 주입이라고 할 수 있다.
🔹횡단 관심사 (cross-cutting concern)
다수의 모듈에서 공통적으로 나타나는 부분 (반복/중복해서 나타남)
ex) 로깅, 보안, 트랙잭션 ...
🔹핵심 관심사
ex) insert, update, delete, select ...
코드 =핵심 관심사 + 횡단 관심사
객체 지향에서 로직(코드)가 있는 곳은 당연히 메서드 내부
➡️ 로직 주입하는 곳은 메서드 내부
- Around - 메서드 전 구역
- Before - 메서드 시작 전 or 시작 직후
- After - 메서드 종료 후 or 종료 직전
- AfterReturning - 메서드 정상 종료 후
- AfterThrowing - 메서드에서 예외가 발생하면서 종료된 후
서비스 추상화 예 - JDBC
어댑터 패턴을 활용하여 데이터베이스 종류에 관계없이 같은 방식으로 제어할 수 있음
: 어댑터 패턴을 적용하여 같은 일을 하는 다수의 기술을 공통의 인터페이스로 제어할 수 있게 한 것
스프링 프레임워크는 서비스 추상화를 위해 다양한 어댑터 제공
ex) OXM, ORM, 캐시, 트랙재션 등에 대한 PSA 제공
일관성 있는 방식으로 서비스 추상화를 해줌 -> PSA
김종민, '스프링 입문을 위한 자바 객체 지향의 원리와 이해', 위키북스 참고