- 본격적으로 스프링에서 사용되는 코드 패턴과 개념에 대해서 파고 들어간다.
IoC/DI
IoC; Inversion of Control
- 제어의 역전
- 객체를 직접 생성하지 않고 외부에서 구현체를 넣어줌으로써 제어권을 거꾸로 가지고 가는 현상
- IoC는 즉, 설계의 패턴이다.
- 실체에 의존할 것인가 추상화에 의존할 것인가
DI; Dependency Injection
- 의존성 주입
- 외부에서 의존성을 받는 행동. 즉, 외부에서 new로 생성된 객체를 받는다.
- DI는 즉, 동작 그 자체다.
- 의존성을 어떻게 가질 것인가?
IoC/DI
- 관계를 짧고 쉽게 정리하자면 → DI를 하면 IoC가 일어난다.
- 객체의 생성, 소멸, 작동의 주도권(즉, 제어권)이 객체 자신에게 있지 않고 외부의 컨테이너에 있다.
AOP
Aspect-Oriented Programming
- 관점 지향적인 프로그래밍 (굳이 해석하자면)
- 공통적인 코드들 (cross-cutting concern)을 묶어서 관리한다.
자바에서의 AOP
- 컴파일 (AspectJ)
JAVA----(AOP)----> Class
- 바이트코드 조작(AspectJ)
JAVA ---- Class ---- (AOP) ---> 메모리
- 프록시 객체를 생성하는 디자인 패턴 → 스프링의 AOP방식
런타임에 프록시 객체를 생성해 기능을 삽입하는 패턴
스프링에서의 AOP
스프링AOP는 로직 주입
이라고 볼 수 있다.- 프록시 패턴을 활용한다.
Proxy pattern
Before: 프록시를 사용하지 않는 코드
// Service.java
public class Service {
public String doSomething(){
return "Work it!";
}
}
// ClientWithDirect.java
public class ClientWithDirect {
public static void main(){
Service service = new Service();
sout(service.doSomething());
}
}
일반적인 객체 사용 방법이다.
After: 프록시를 사용하도록 변경
//ServiceInterface.java
public interface ServiceInterface {
String doSomething()
}
//Service.java
public class Service implements ServiceInterface{
public String doSomething(){
return "Work it!";
}
}
//Proxy.java
public class Proxy implements ServiceInterface {
ServiceInterface service; // ← DIP 가능
public String doSomething(){
sout("Service가 실행되기 전에 뭔갈 넣을수도 있고");
service = new Service();
sout("생성자 뒤에도 가능하지.");
return service.doSomething();
}
}
//ClientWithProxy.java
public class ClientWithProxy{
public static void main(){
ServiceInterface proxy = new Proxy(); // ← OCP
sout(proxy.doSomething());
}
}
이렇게하면 다른 서비스를 구현하더라도 프록시 코드를 통해 영향을 받지 않을 수 있다.
- 프록시 패턴의 객체를 사용할때 최상위 객체를 불러오는게 아니라 비즈니스 로직의 구현체를 타입으로 지정한다.
ServiceInterface proxy
- 생성자는 프록시 구현체를 지정한다
new Proxy()