with-RL
프로그램 / Java2024년 1월 20일

Spring Boot Micro Service Architecture 만들기 (1)

이 포스트는 Spring Boots와 Netflix Eureka를 이용해서 간단한 MSA (Micro Service Architecture)를 만들어 보는 과정에 대한 설명입니다.

이 과정은 다음 환경에서 구성했습니다.

1. Gradle 설치

$ gradle

2. my-msa 프로젝트 생성

$ gradle init
subprojects {
    group = 'com.mymsa'
    version = '1.0.0'

    repositories {
        mavenCentral()
    }
}

3. app-core 프로젝트 생성하기

rootProject.name = 'my-msa'

include 'app-core'
plugins {
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.mymsa.core'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'

    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:2021.0.4"
    }
}

bootJar {
    enabled = false
}
jar {
    enabled = true
}

tasks.named('test') {
    useJUnitPlatform()
}

4. app-eureka 프로젝트 생성하기

rootProject.name = 'my-msa'

include 'app-core'
include 'app-eureka'
plugins {
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.mymsa.eureka'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:2021.0.4"
    }
}

bootJar {
    enabled = true
}
jar {
    enabled = false
}

tasks.named('test') {
    useJUnitPlatform()
}
spring:
  profiles:
    active: local
  application:
    name: app-eureka

---
# local
server:
  port: 9000

spring:
  config:
    activate:
      on-profile: local

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    serviceUrl:
      defaultZone: http://localhost:${server.port}/eureka
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
    <property name="PROFILE" value="${spring.profiles.active}" />

    <!-- Console Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|%t|%level|%logger{36}|%msg%n</Pattern>
        </layout>
    </appender>

    <root level="INFO">
        <springProfile name="local">
            <appender-ref ref="CONSOLE"/>
        </springProfile>
    </root>
</configuration>
package com.mymsa.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }

}

5. app-gateway 프로젝트 생성하기

rootProject.name = 'my-msa'

include 'app-core'
include 'app-eureka'
include 'app-gateway'
plugins {
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.mymsa.gateway'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation project(':app-core')
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:2021.0.4"
    }
}

bootJar {
    enabled = true
}
jar {
    enabled = false
}

tasks.named('test') {
    useJUnitPlatform()
}
spring:
  profiles:
    active: local
  application:
    name: app-gateway
  cloud:
    loadbalancer:
      ribbon:
        enabled: false
    gateway:
      routes:
        - id: app-web
          predicates:
            - Path=/app-web/**
          uri: lb://app-web

---
# local
server:
  port: 9001

spring:
  config:
    activate:
      on-profile: local

eureka:
  instance:
    instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
    lease-renewal-interval-in-seconds: 10
    lease-expiration-duration-in-seconds: 2
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:9000/eureka/
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
    <property name="PROFILE" value="${spring.profiles.active}" />

    <!-- Console Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|%t|%level|%logger{36}|%msg%n</Pattern>
        </layout>
    </appender>

    <root level="INFO">
        <springProfile name="local">
            <appender-ref ref="CONSOLE"/>
        </springProfile>
    </root>
</configuration>
package com.mymsa.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

}

6. app-web 프로젝트 생성하기

rootProject.name = 'my-msa'

include 'app-core'
include 'app-eureka'
include 'app-gateway'
include 'app-web'
plugins {
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.mymsa.web'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation project(':app-core')
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'

    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:2021.0.4"
    }
}

bootJar {
    enabled = true
}
jar {
    enabled = false
}

tasks.named('test') {
    useJUnitPlatform()
}
spring:
  profiles:
    active: local
  application:
    name: app-web

---
# local
server:
  port: 0

spring:
  config:
    activate:
      on-profile: local

eureka:
  instance:
    instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
    lease-renewal-interval-in-seconds: 10
    lease-expiration-duration-in-seconds: 2
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:9000/eureka/
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
    <property name="PROFILE" value="${spring.profiles.active}" />

    <!-- Console Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|%t|%level|%logger{36}|%msg%n</Pattern>
        </layout>
    </appender>

    <root level="INFO">
        <springProfile name="local">
            <appender-ref ref="CONSOLE"/>
        </springProfile>
    </root>
</configuration>
package com.mymsa.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class WebApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }

}
package com.mymsa.web.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RequestMapping("/app-web")
@RestController
@Slf4j
public class HelloController {

    @GetMapping("/hello")
    public Mono<String> hello() {
        log.info("hello-request received");
        return Mono.just("Hello: " + System.currentTimeMillis());
    }

}

참고

이 포스트와 관련 포스트 입니다.

Spring Boot Micro Service Architecture 만들기 (1) | with-RL