-
Notifications
You must be signed in to change notification settings - Fork 3
Admin 멀티 모듈 적용
-
api
랑admin
은 따로 띄우는 것이다❗️- 아예 격리된 망에서 띄우는 것이다. 같이 있으면 안된다.
- 별도의 애플리케이션을 띄우는 것이다 !!
- 외부에서 들어오는 요청(송금, . . . )
- 외부 클라이언트가 api 서버에서
/admin
을 한다고 admin 서버에 접속할 수 없다 ❌
- 외부 클라이언트가 api 서버에서
-
admin 서버
-
public IP
로 들어오는 요청을 받지 않는다. 회사 내부망에서만 접속이 가능하다. 당연한 말이지만, 일반 사용자는 admin 서버가 있는지도 모르게 해야 한다. - api와는 별도의 애플리케이션
-
- 같은 domain을 의존해야 하나요?
- yes. domain 재사용 하려고 멀티 모듈을 적용한 것이다.
- Security Config
hasRole
- Admin을 hasRole로 구분할 필요는 없다 ❌
- 어차피 다른 서버이다 !
- 공통 코드 추출 ❗️ 재사용성 ❗️
-
api
와admin
이 멀티 모듈로 관리되지 않을 때 테이블의 변경사항이 발생한다면?- 주로 클라이언트에 가까운
api
에서 변경이 자주 발생한다.- ex) 컬럼 추가
- api쪽 db에 변경이 발생할 때마다
admin
db에도 똑같은 작업을 반복 수행해주어야 한다.
- 주로 클라이언트에 가까운
- 멀티 모듈 적용 시
api
와admin
은domain
모듈을 함께 사용한다.-
domain
이 한 번만 변경될 것이다. 같은domain
모듈에 의존하고 있기 때문이다 ❗️
-
-
common
- 🙅 공통 로직을 전부 다 여기다 쓴다. → 계속 커진다.
-
God Object
: 모든 걸 다 갖고 있는 모듈을 경계해야 한다. - 이 코드는
admin
에도 있어야 할 것 같고api
에도 있어야 할 것 같은데?- → 이러면서 코드가 **
common
**에 계속해서 추가된다. - 그럼 모듈을 나누는 게 의미가 없어질 수가 있다. 😵
- → 이러면서 코드가 **
- **“공통”**이라는 것은 결속력이 없다.
-
domain
-
Entity
,Repository
만 있다. → 역할이 명확하다. - 나눠야 하는 이유: 재사용성이 높아서 !!
-
build.gradle(root)
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.3'
id 'io.spring.dependency-management' version '1.1.6'
id 'java-library'
}
allprojects {
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'java-library'
dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
repositories {
mavenCentral()
}
tasks.named('test') {
useJUnitPlatform()
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
}
bootJar {
enabled = false
}
jar {
enabled = false
}
build.gradle(badminton-api)
dependencies {
implementation project(':badminton-domain')
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.6.0'
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation group: 'me.paulschwarz', name: 'spring-dotenv', version: '4.0.0'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
testImplementation 'org.springframework.security:spring-security-test'
}
test {
useJUnitPlatform()
}
bootJar {
enabled = true
}
jar {
enabled = false
}
build.gradle(badminton-domain)
dependencies {
api('org.springframework.boot:spring-boot-starter-data-jpa')
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.security:spring-security-test'
runtimeOnly 'com.mysql:mysql-connector-j'
implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.6.0'
}
bootJar {
enabled = false
}
jar {
enabled = true
}
변경 전에는 build.gradle(badminton-api)에
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
의존성이 추가되어 있다.
이를 아래와 같이 바꿔보자.
plugin에 `id 'java-library`` 를 추가하고, build.gradle(badminton-domain)에서 JPA 의존성을 추가하는 부분을 아래와 같이 수정한다.
api 'org.springframework.boot:spring-boot-starter-data-jpa'
이렇게 하면 api 모듈에 의존성이 전이되어 JPA 기능을 사용할 수 있다.
다만, 이를 남용하면 안된다. 왠만하면 implementation
으로 쓰는 것이 좋다. api를 쓰면 의존성이 전이된다.
API가 필요로 하는 JPA의 기능을 domain
모듈에 Adapter로 만들면 된다.
domain
에 어댑터 클래스를 하나 만든다. 어댑터 클래스가 JPA의 기능을 내부적으로 들고 있는 것이다. api 모듈이 JPA에 의존을 안하고 domain에 있는 adapter를 쓰면 된다. api 모듈은 JPA를 몰라도, 기능을 사용할 수 있다.
api
는 domain
에 의존하고 있으니 domain
의 영향을 받는다.
모듈 빌드를 하면 jar
파일이 생긴다. 의존을 안하게 만들면 빌드를 안해도 된다❗️
외부 의존이 필요할 때 이를 한 번 감싸서 실제적인 것에 의존하지 않도록 하는 것이 **adapter pattern
**이다.
인터페이스에서 메서드를 정의할 때 메서드 header
만 정의한다. 구현(body
)을 정의하지 않는다. body
가 변경되지 않기 떄문에 이를 추상화라고 하는 것이다.
구현이 바뀔 때 B
가 바뀌고, A
는 변하지 않는다. 의존성의 흐름이 B → A
로 흐르기 떄문이다.
DIP
가 되면 의존을 받는 것이 아니라 의존을 하는 것이다.
header
가 바뀌면? 이때는 당연히 영향이 갈 것이다. 그러나 header
가 바뀔 확률은 body
가 바뀔 확률보다 훨씬 낮다.