implementation은 의존성 전파가 되지 않는다.
문제 상황
db 모듈에는 Jpa 관련 dependency를 implementation으로 추가했다.
api 모듈에서는 추가하지 않은 상태에서 사용하려고 하면 당연히 에러가 발생한다.
이유는 api 모듈에서는 jpa 관련 아무런 정보(의존성)가 없기 때문이다.
해결 방법
방법 1. api 모듈에도 jpa 의존성을 추가 (권장 o)
dependencies {
implementation project(':db')
}
방법 2. db에 api 스코프로 의존성을 추가 (권장 x)
// db 모듈의 build.gradle
dependencies {
api 'org.springframework.boot:spring-boot-starter-data-jpa'
}
만약 api를 사용하려는데 해당 에러가 발생한다면?
api 키워드를 사용하려면 build.gradle의 플러그인을 추가해줘야한다.
plugins {
...
id 'java-library'
}
implementation과 api 관련해서는 여기에다가 포스팅해놨으니 참고바란다.
https://k9want.tistory.com/entry/Gradle-dependency-implementation%EA%B3%BC-api-%EC%B0%A8%EC%9D%B4
다른 모듈의 Bean을 쓰고 싶다면? config
문제 상황
스프링의 컴포넌트 스캔은 해당 애플리케이션을 실행(@SpringBootApplication)시키는 패키지를 기준으로 컴포넌트(빈) 스캔이 일어난다.
즉, 스프링은 해당 애플리케이션을 실행시키는 자신과 동일한 경로에 있는 패키지에 있는 Bean들을 자신의 Bean으로 등록한다.
ex) ApiApplication의 패키지를 기준으로 컴포넌트 스캔이 일어난다. (기준 패키지 : org.delivery.api)
여기서 문제가 발생한다.
문제는 api에서 db의 AccountRepository(Bean)을 사용하고 싶은데 패키지명이 달라서 api에서 사용할 수가 없다.
(org.delivery.api != org.delivery.db)
해결 방법
방법1. config를 사용해서 db 하위의 컴포넌트를 api에서 빈으로 등록하기
api 모듈의 config클래스에서 @ComponentScan 등과 같은 어노테이션을 사용하여 db 모듈의 패키지를 명시적으로 스캔 대상에 포함시킬 수 있다. 이렇게 하면 db 모듈의 AccountRepository 컴포넌트를 api 모듈의 스프링 컨텍스트에 빈으로 등록할 수 있다.
[자동 빈 등록 방식- db 관련일 경우]
db에는 Entity와 Repository 관련된 내용만을 둘 예정이기에 이렇게 작성했다.
config 패키지에서 @Configuration 클래스를 만들거나
아니면 @Configuration -> @SpringBootConfiguration -> @SpringBootApplication
즉, @Configuration을 어노테이션을 상속받고 있는
@SpringBootApplication 어노테이션이 있는 main 메서드에서 명시적으로 지정하여
스프링이 자동으로 빈을 등록하고 스캔할 수 있게끔 할 수 있다.
[자동 빈 등록 방식 - common]
@SpringBootApplication의 scanBasePackages에 컴포넌트 스캔할 패키지들을 명시적으로 작성하여 자동 빈 등록이 되게끔 할 수 있다.
[직접 빈 등록 방식 예시] @Bean 어노테이션을 사용
@Configuration
public class ApiModuleConfig {
@Bean
public AccountRepository accountRepository() {
// AccountRepository 인스턴스 생성 또는 참조하여 반환
}
}
중요한 건 다른 모듈에서 정의된 컴포넌트를 현재 모듈의 스프링 컨텍스트에 빈으로 등록하고 싶을 때에는 config를 통해서 빈을 등록하고 사용할 수 있다는 것이다.
스프링 프레임워크에서 '빈으로 등록한다'는 것은 해당 객체를 스프링 애플리케이션 컨텍스트에서 관리할 수 있는 객체로 만들고, 이를 애플리케이션 전반에서 필요할 때 재사용할 수 있게 한다는 의미입니다. 스프링 컨텍스트에 빈으로 등록된 객체는 스프링의 의존성 주입(Dependency Injection) 기능을 통해 다른 컴포넌트에 주입되어 사용될 수 있습니다.
빈으로 등록된 객체는 다음과 같은 특징을 가집니다:
- 싱글턴 관리: 기본적으로 스프링은 빈을 싱글턴으로 관리합니다. 즉, 애플리케이션 컨텍스트 내에서 요청될 때마다 동일한 인스턴스를 반환합니다. 이는 메모리 사용을 최적화하고, 인스턴스 간의 공유 상태를 관리하기 용이하게 합니다.
- 의존성 주입: 빈으로 등록된 객체는 스프링의 의존성 주입 기능을 통해 자동으로 관련된 객체에 주입될 수 있습니다. 이를 통해 모듈 간의 결합도를 낮추고, 코드의 재사용성과 유지 보수성을 향상시킬 수 있습니다.
- 생명주기 관리: 스프링 컨텍스트는 빈의 생명주기를 관리합니다. 이는 빈이 생성되고, 사용되며, 소멸하는 과정에 있어서 필요한 로직을 실행할 수 있게 해줍니다. 예를 들어, @PostConstruct와 @PreDestroy 어노테이션을 사용하여 빈의 초기화 및 소멸 로직을 정의할 수 있습니다.
따라서, 특정 컴포넌트(예: AccountRepository)를 빈으로 등록하면, 그 컴포넌트는 스프링의 관리 하에 들어가 애플리케이션 내에서 필요한 곳에 자동으로 주입되어 사용될 수 있습니다. 이는 스프링이 제공하는 IoC(Inversion of Control) 컨테이너의 핵심 기능 중 하나입니다.
방법2. 패키지명을 동일하게 유지하기
org.delivery.db -> org.delivery.api
이 방법은 패키지 이름을 통일하여 자동 컴포넌트 스캔의 범위 내에 두는 것이다.
하지만, 이 방법은 모듈 간의 명확한 경계를 흐리게 하며, 오히려 관리가 복잡해질 수 있다.
각 모듈이 독립적인 기능 단위로 존재하는 것이 바람직하며, 패키지 이름을 강제로 일치시키는 것은 권장하지 않는다.
방법3. 공통된 path에다가 스프링을 실행시키기
org.delivery.db & org.delivery.api => org.delivery
둘의 공통적인 패키지 기준인 org.delivery에다가 스프링을 실행시키는 Main메서드를 두는 것이다.
앞서 말햇듯 @SpringBootApplication 즉, 스프링을 실행시키는 녀석을 기준으로 패키지 하위의 있는 녀석들을 빈으로 등록하기에 공통의 Path를 맞추는 것으로도 해결할 수 있다.
이 또한 방법2와 같은 방식이기에
각 모듈이 독립적인 기능 단위로 존재하는 것이 바람직하며, 패키지 이름을 강제로 일치시키는 것은 권장하지 않는다.
추가 방법
- @ComponentScan을 사용하는 것은 분리된 모듈 간의 명시적인 의존성을 관리하는 데 도움이 될 수 있지만, 모듈 간의 결합도를 높일 수 있으므로 주의해서 사용해야 한다.
- 모듈 간의 의존성을 명확히 관리하고자 할 때는, Spring의 @Import 어노테이션을 사용하여 다른 구성 클래스를 직접 가져오는 방법도 고려할 수 있다.
- 또 다른 방법으로, api 모듈에서 db 모듈의 빈을 직접 @Bean 메서드를 통해 등록하는 방법도 있다. 이 경우, db 모듈의 Java 설정 파일을 api 모듈에서 직접 참조해야 한다.
'Spring' 카테고리의 다른 글
[Spring] ObjectMapper 커스텀해서 사용해보기 (feat. serialization) (0) | 2024.03.20 |
---|---|
[Spring] Swagger (0) | 2024.03.19 |
[Spring] 멀티 모듈 (1) - 스프링부트 프로젝트에 멀티모듈 설정하기 (feat. build.gradle) (0) | 2024.03.19 |
(임시)[Spring] Spring 비동기 끄적이는중... (1) | 2024.03.18 |
[Spring] 스프링 부트 Dependency Versions 확인하기 (0) | 2023.10.03 |