스프링 삼각형
POJO(Plain Old Java Object)
진정한 POJO란 객체지향적인 원리에 충실하면서, 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트
1. IoC(Inversion of Control)
IoC의 분류
*DL 사용시 컨테이너 종속이 증가하기 때문에 주로 DI를 사용한다.
IoC 장점
2. DI(Dependency Injection)
의존성 주입을 해야하는 이유
의존성 주입의 3가지 방법
2-1. 생성자 주입(Constructor Injection)
@Controller
public class ExampleController {
private final ExampleService exampleService;
public ExampleController(ExampleService exampleService) {
this.exampleService = exampleService;
}
}
2-2. 필드 주입(Field Injection)
@Controller
public class ExampleController {
@Autowired
private ExampleService exampleService;
}
단점
2-3. 수정자 주입(Setter Injection)
@Controller
public class ExampleController {
private ExampleService exampleService;
@Autowired
public void setExampleService(ExampleService exampleService) {
this.exampleService = exampleService;
}
}
단점
2-4. 권장 주입 방식
생성자를 통한 주입 방식
1. 순환 참조를 방지할 수 있다.
개발을 하다 보면 여러 컴포넌트 간에 의존성이 생긴다.
ex) A가 B를 참조하고, B가 다시 A를 참조하는 순환 참조되는 코드
@Service
public class AService {
//순환참조
@Autowired
private Bservice bService;
public void HelloA() {
bService.HelloB();
}
}
@Service
public class BService {
//순환참조
private AService aService;
public void HelloB() {
aService.HelloA();
}
}
필드 주입과 수정주 주입은 빈이 생성된 후에 참조를 하기 때문에 어플리케이션이 아무런 오류 그리고 경고 없이 구동된다. 즉, 실제 코드가 호출될 때까지 문제를 알 수 없다는 의미이다.
반면, 생성자를 통해 주입하고 실행하면 BeanCurrentlyInCreationException이 발생하게 됩니다.
순환 참조 뿐만아니라 더 나아가서 의존 관계에 내용을 외부로 노출 시킴으로써 어플리케이션을 실행하는 시점에서 오류를 체크할 수 있다.
2. 불변성(Immutability)
@Controller
public class ExampleController {
private final ExampleService exampleService;
public ExampleController(ExampleService exampleService) {
this.exampleService = exampleService;
}
}
생성자로 의존성을 주입할 때 final로 선언할 수 있고, 이로인해 런타임에서 의존성을 주입받는 객체가 변할 일이 없어지게 된다.
하지만 수정자 주입이나 일반 메소드 주입을 이용하게 되면 불필요하게 수정의 가능성을 열어두게 되고, 이는 OOP의 5가지 원칙 중 OCP(Open-Closed-Principal,개방-패쇄의 원칙)를 위반하게 됩니다.
그러므로 생성자 주입을 통해 변경의 가능성을 배제하고 불변성을 보장하는 것이 좋다.
또한,필드 주입 방식은 null이 만들어질 가능성이 있는데, final로 선언한 생성자 주입 방식은 null이 불가능하다.
3. 테스트에 용이하다.
생성자 주입을 사용하게 되면 테스트 코드를 좀 더 편리하게 작성할 수 있다.
DI의 핵심은 관리되는 클래스가 DI 컨테이너에 의존성이 없어야 한다는 것이다.
즉, 독립적으로 인스턴스화가 가능한 POJO(Plain Old Java Object)여야 한다는 것이다.
위와 같은 이유로 필드 주입이나 수정자 주입보다는 생성자 주입의 사용을 권장한다.
3. AOP(Aspect Oriented Programming)
4. PSA(Portable Service Abstraction)
서비스 추상화라는 의미이다.
서비스의 내용을 모르더라도 해당 서비스를 이용할 수 있다는 것을 의미한다.
예를 들어, JDBC Driver를 사용해 데이터베이스에 접근하지만 JDBC Driver가 어떻게 구현되어 있는지는 관심이 없다.
실제 구현부를 추상화 계층으로 숨기고 핵심적인 요소만 개발자에게 제공함으로써 실제 구현부를 모르더라도 해당 서비스를 이용할 수 있도록 하는 것이다.
Portable 은 휴대용이라는 뜻으로 JDBC Driver 종류를 mysql driver에서 oracle driver로 변경한다고 해서 프로젝트의 비지니스 로직에 변화가 없다는 것이다.
이런 기능이 가능한 것은 추상화 계층의 존재 때문이다.
모든 JDBC Driver는 공통적인 인터페이스를 가지고 있기 때문에 해당 인터페이스를 구현하는 어떤 것으로 대체되든 프로젝트에 영향이 없어지는 것이다.
Spring PSA는 확장에는 열려있고 수정에는 닫혀있어야 한다는 OCP의 대표적인 예시라고 할 수 있다.(객체지향 SOLID원칙)
Reference :
https://dev-coco.tistory.com/80?category=1009530
https://ch4njun.tistory.com/270