모든 의존성은 애플리케이션의 도메인 코드 방향으로 향해야 도메인 코드가 바깥 계층의 변경으로부터 안전하다!
유스케이스가 영속성 어댑터를 직접 호출하고 스스로 인스턴스화 한다면 의존성 방향이 잘못되게 된다.
클래스가 필요로 하는 모든 객체를 생성자로 전달한다면 테스트하기 더 용이하다.
그러면 결국 누군가 객체 인스턴스를 생성해야할텐데… 누가 책임을 가지게 되는가?
설정 컴포넌트 → 아키텍처에 대해 중립적이고 인스턴스 생성을 위해 모든 클래스에 대한 의존성을 가진다.
설정 컴포넌트는 클린 아키텍처 구조에서 원의 가장 바깥쪽에 위치!
설정 컴포넌트는 애플리케이션을 조립하는 것을 책임진다. (우리가 설정한대로!) 세부적으로는 아래와 같은 역할을 수행한다.
- 웹 어댑터 인스턴스 생성
- HTTP 요청이 실제로 웹 어댑터로 전달되도록 보장
- 유스케이스 인스턴스 생성
- 웹 어댑터에 유스케이스 인스턴스 제공
- 영속성 어댑터 인스턴스 생성
- 유스케이스에 영속성 어댑터 인스턴스 제공
- 영속성 어댑터가 실제로 데이터베이스에 접근할 수 있도록 보장
또한 설정 컴포넌트는 설정 파일이나 커맨드라인 파라미터 등과 같은 설정 파라미터의 소스에도 접근 가능해야한다!
사실 설정 컴포넌트는 책임이 굉장히 많다. → SRP 위반일까?
자바의 main 메서드 안에서 웹 컨트롤러부터 영속성 어댑터까지, 필요한 모든 클래스의 인스턴스를 생성한 후 연결한다. 뿐만 아니라 웹 컨트롤러를 HTTP로 노출시키는 로직도 필요하다.
애플리케이션을 조립하는 가장 기본적인 방법이다.
하지만 단점이 존재한다.
package-private 의존성을 유지하면서 지저분한 작업들을 대신해주는 의존성 주입 프레임워크들이 존재한다.
애플리케이션 컨텍스트 → 스프링을 이용해서 애플리케이션을 조립한 결과물
Bean → 애플리케이션을 구성하는 모든 객체
스프링은 classpath Scanning으로 classpath에서 접근 가능한 모든 클래스를 확인해서 @Component가 붙은 클래스를 찾는다. 그리고 이러한 클래스들의 인스턴스를 모두 만들어 애플리케이션 컨텍스트에 추가한다.
JVM 혹은 자바 컴파일러가 클래스나 패키지를 찾을 때 기준이 되는 경로를 말한다.
소스 코드(.java)를 컴파일 후 바이트코드(.class)로 변환하고, JVM이 바이트코드로 된 파일을 실행하려면 찾아야 하는데 이 바이트코드까지의 경로를 클래스패스라고 한다.
@Component를 활용해서 메타-애너테이션으로 임의의 정보를 더 표현하는 애너테이션을 만들어서 사용할 수도 있다. (책 내의 @PersistenceAdapter)
classpath Scanning은 단점이 존재한다.
즉, classpath Scanning + @Component 방식은 애플리케이션 내의 모든 관계를 파악하기 매우 어렵다. 그 관련된 설정 정보가 전부 흩어져있기 때문이다!
애플리케이션 컨텍스트에 추가할 빈을 생성하는 설정 클래스를 만드는 방식이다.
@Configuration을 통해서 스프링의 classpath scanning에서 발견해야할 설정 클래스임을 표시한다.
@Bean가 붙은 팩터리 메서드를 통해 빈 생성
@EnabledJpaRepositories를 사용하면 우리가 정의한 모든 스프링 데이터 리포지토리 인터페이스의 구현체를 생성해서 제공한다.
또한 특정 모듈에 대한 설정 클래스를 따로 두어, 특정 모듈만 포함하고 그 다른 모듈의 빈은 모킹해서 애플리케이션 컨텍스트를 만들 수 있다. → 테스트에 큰 유연성
또한 애플리케이션 계층을 스프링 프레임워크에 대한 의존성 없이 깔끔하게 유지할 수 있다. @Component를 여기저기에 안붙여도 되기 때문!
하지만 문제점도 존재한다.
스프링은 우리가 제공하는 부품들을 이용해서 애플리케이션을 조립해준다.
이런 기능을 통해 애플리케이션 전체를 고민하지 않고도 빠르게 개발할 수 있다.
애플리케이션 조립을 책임지는 전용 설정 컴포넌트를 만들면, 서로 다른 모듈로부터 독립되어 코드 상에서 손쉽게 옮겨 다닐 수 있는 응집도 높은 모듈을 만들 수 있다. 물론 설정 컴포넌트를 유지보수하는데의 cost가 생긴다.