From 6b248c6a6921ecfe77e2f6042ce9163f6e58c525 Mon Sep 17 00:00:00 2001 From: accura0117 Date: Fri, 27 Mar 2026 14:37:57 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20Embedded=20Redis=20=EC=A0=81=EC=9A=A9?= =?UTF-8?q?=20=E2=80=94=20Docker=20=EC=97=86=EC=9D=B4=20Redis=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EA=B5=AC=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - EmbeddedRedisConfig: 외부 Redis 없으면 Embedded Redis 자동 시작 - RedisCacheAutoConfig: Redis 연결 실패 시 인메모리 캐시 fallback - install.bat/sh: Docker/Redis 필수 의존성 제거, 인메모리 전환 안내 - application yml: Redis 설정을 선택 사항으로 변경 Co-Authored-By: Claude Opus 4.6 (1M context) --- wbx-spring-core/build.gradle | 6 ++ wbx-spring-core/scripts/install.bat | 24 ++----- wbx-spring-core/scripts/install.sh | 19 ++---- .../spring/config/EmbeddedRedisConfig.java | 68 +++++++++++++++++++ .../spring/config/RedisCacheAutoConfig.java | 42 ++++++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 2 + .../main/resources/application-example.yml | 9 +-- .../src/main/resources/application-test.yml | 5 -- 8 files changed, 131 insertions(+), 44 deletions(-) create mode 100644 wbx-spring-core/src/main/java/kr/co/accura/wbx/spring/config/EmbeddedRedisConfig.java create mode 100644 wbx-spring-core/src/main/java/kr/co/accura/wbx/spring/config/RedisCacheAutoConfig.java diff --git a/wbx-spring-core/build.gradle b/wbx-spring-core/build.gradle index d126c33..312f39b 100644 --- a/wbx-spring-core/build.gradle +++ b/wbx-spring-core/build.gradle @@ -34,6 +34,12 @@ dependencies { compileOnly 'com.oracle.database.jdbc:ojdbc11:23.6.0.24.10' compileOnly 'com.microsoft.sqlserver:mssql-jdbc:12.8.1.jre11' + // Embedded Redis (Docker 없이 Redis 자동 구동) + api('it.ozimov:embedded-redis:0.7.3') { + exclude group: 'org.slf4j' + exclude group: 'ch.qos.logback' + } + // Micrometer runtimeOnly 'io.micrometer:micrometer-registry-prometheus' diff --git a/wbx-spring-core/scripts/install.bat b/wbx-spring-core/scripts/install.bat index 1ea1d22..76fb17a 100644 --- a/wbx-spring-core/scripts/install.bat +++ b/wbx-spring-core/scripts/install.bat @@ -85,7 +85,7 @@ where docker >nul 2>&1 if !ERRORLEVEL! equ 0 ( for /f "delims=" %%d in ('docker --version') do echo [OK] %%d ) else ( - echo [WARN] Docker 미설치 — DB/Redis를 직접 설치해야 합니다 + echo [INFO] Docker 미설치 — DB를 직접 설치해야 합니다 ) :: ---------- 4. Redis 확인 ---------- @@ -100,23 +100,7 @@ if !ERRORLEVEL! equ 0 ( ) ) if !REDIS_OK! equ 0 ( - where docker >nul 2>&1 - if !ERRORLEVEL! equ 0 ( - docker ps --format "{{.Names}}" 2>nul | findstr /i "redis" >nul 2>&1 - if !ERRORLEVEL! equ 0 ( - echo [OK] Redis Docker 컨테이너 실행 중 - ) else ( - echo [INFO] Redis 미실행 — Docker로 자동 시작... - docker run -d --name redis -p 6379:6379 redis:7-alpine >nul 2>&1 - if !ERRORLEVEL! equ 0 ( - echo [OK] Redis 컨테이너 시작 완료 - ) else ( - echo [WARN] Redis 자동 시작 실패 — 수동으로 Redis를 실행하세요 - ) - ) - ) else ( - echo [WARN] Redis 연결 불가 — Redis를 설치/실행하세요 - ) + echo [INFO] Redis 미실행 — 인메모리 캐시로 자동 전환됩니다 (운영 환경에서는 Redis 권장^) ) :: ---------- 5. MySQL 연결 확인 ---------- @@ -170,8 +154,8 @@ if not exist "!PROJECT_ROOT!\.env" ( echo DB_USER=jsh echo DB_PASS=jsh@ echo. - echo # --- Redis --- - echo SPRING_DATA_REDIS_HOST=localhost + echo # --- Redis (선택 — 미설정 시 인메모리 캐시 자동 사용) --- + echo # SPRING_DATA_REDIS_HOST=localhost echo. echo # --- CORS --- echo CORS_ORIGINS=https://app.company.com diff --git a/wbx-spring-core/scripts/install.sh b/wbx-spring-core/scripts/install.sh index a534992..f2f6e4d 100644 --- a/wbx-spring-core/scripts/install.sh +++ b/wbx-spring-core/scripts/install.sh @@ -136,7 +136,7 @@ echo "3. Docker 확인 (선택)" if command -v docker &>/dev/null; then ok "$(docker --version | head -1)" else - warn "Docker 미설치 — DB/Redis를 직접 설치해야 합니다" + info "Docker 미설치 — DB를 직접 설치해야 합니다" fi # ---------- 4. Redis 확인 ---------- @@ -145,19 +145,8 @@ REDIS_HOST="${SPRING_DATA_REDIS_HOST:-localhost}" REDIS_PORT="${SPRING_DATA_REDIS_PORT:-6379}" if command -v redis-cli &>/dev/null && redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ping 2>/dev/null | grep -q PONG; then ok "Redis 응답 OK ($REDIS_HOST:$REDIS_PORT)" -elif command -v docker &>/dev/null; then - if docker ps --format '{{.Names}}' 2>/dev/null | grep -q redis; then - ok "Redis Docker 컨테이너 실행 중" - else - info "Redis 미실행 — Docker로 자동 시작..." - if docker run -d --name redis -p "${REDIS_PORT}:6379" redis:7-alpine &>/dev/null; then - ok "Redis 컨테이너 시작 완료" - else - warn "Redis 자동 시작 실패 — 수동으로 Redis를 실행하세요" - fi - fi else - warn "Redis 연결 불가 ($REDIS_HOST:$REDIS_PORT) — Redis를 설치/실행하세요" + info "Redis 미실행 — 인메모리 캐시로 자동 전환됩니다 (운영 환경에서는 Redis 권장)" fi # ---------- 5. MySQL 연결 확인 ---------- @@ -213,8 +202,8 @@ DB_NAME=mos DB_USER=jsh DB_PASS=jsh@ -# --- Redis --- -SPRING_DATA_REDIS_HOST=localhost +# --- Redis (선택 — 미설정 시 인메모리 캐시 자동 사용) --- +# SPRING_DATA_REDIS_HOST=localhost # --- CORS --- CORS_ORIGINS=https://app.company.com diff --git a/wbx-spring-core/src/main/java/kr/co/accura/wbx/spring/config/EmbeddedRedisConfig.java b/wbx-spring-core/src/main/java/kr/co/accura/wbx/spring/config/EmbeddedRedisConfig.java new file mode 100644 index 0000000..0cb1caa --- /dev/null +++ b/wbx-spring-core/src/main/java/kr/co/accura/wbx/spring/config/EmbeddedRedisConfig.java @@ -0,0 +1,68 @@ +package kr.co.accura.wbx.spring.config; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import redis.embedded.RedisServer; + +import java.net.Socket; + +/** + * Embedded Redis 자동 구성. + * + * 동작 순서: + * 1. 외부 Redis가 이미 실행 중이면 → 그대로 사용 (운영 환경) + * 2. 외부 Redis 없으면 → Embedded Redis 자동 시작 (개발 환경) + * 3. Embedded Redis도 실패하면 → RedisCacheAutoConfig에서 인메모리 캐시 전환 + * + * Docker Desktop 없이 개발 PC에서 Redis가 자동 구동됩니다. + */ +@Configuration +public class EmbeddedRedisConfig { + + private static final Logger log = LoggerFactory.getLogger(EmbeddedRedisConfig.class); + + @Value("${spring.data.redis.port:6379}") + private int redisPort; + + private RedisServer redisServer; + + @PostConstruct + public void start() { + if (isRedisRunning()) { + log.info("[WBX] 외부 Redis 감지 — Embedded Redis 건너뜀 (port: {})", redisPort); + return; + } + try { + redisServer = RedisServer.builder() + .port(redisPort) + .setting("maxmemory 128mb") + .setting("maxmemory-policy allkeys-lru") + .build(); + redisServer.start(); + log.info("[WBX] Embedded Redis 시작 (port: {})", redisPort); + } catch (Exception e) { + log.warn("[WBX] Embedded Redis 시작 실패 — 인메모리 캐시로 전환됩니다 ({})", e.getMessage()); + redisServer = null; + } + } + + @PreDestroy + public void stop() { + if (redisServer != null && redisServer.isActive()) { + redisServer.stop(); + log.info("[WBX] Embedded Redis 종료"); + } + } + + private boolean isRedisRunning() { + try (Socket socket = new Socket("localhost", redisPort)) { + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/wbx-spring-core/src/main/java/kr/co/accura/wbx/spring/config/RedisCacheAutoConfig.java b/wbx-spring-core/src/main/java/kr/co/accura/wbx/spring/config/RedisCacheAutoConfig.java new file mode 100644 index 0000000..faf9304 --- /dev/null +++ b/wbx-spring-core/src/main/java/kr/co/accura/wbx/spring/config/RedisCacheAutoConfig.java @@ -0,0 +1,42 @@ +package kr.co.accura.wbx.spring.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; +import org.springframework.cache.CacheManager; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; + +/** + * Redis/인메모리 캐시 자동 구성. + * + * 동작 방식: + * 1. Redis 연결 가능 → RedisCacheManager 사용 + * 2. Redis 연결 불가 → ConcurrentMapCacheManager 자동 전환 (인메모리) + * + * 개발 PC에서 Docker/Redis 없이도 애플리케이션이 정상 구동됩니다. + */ +@Configuration +@AutoConfigureBefore(CacheAutoConfiguration.class) +public class RedisCacheAutoConfig { + + private static final Logger log = LoggerFactory.getLogger(RedisCacheAutoConfig.class); + + @Bean + @Primary + public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { + try { + redisConnectionFactory.getConnection().close(); + log.info("[WBX] Redis 캐시 사용 (연결 성공)"); + return RedisCacheManager.builder(redisConnectionFactory).build(); + } catch (Exception e) { + log.warn("[WBX] Redis 연결 실패 — 인메모리 캐시로 전환 ({})", e.getMessage()); + return new ConcurrentMapCacheManager("permissions", "deptScopes"); + } + } +} diff --git a/wbx-spring-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/wbx-spring-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index c0db889..4cefd95 100644 --- a/wbx-spring-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/wbx-spring-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,2 +1,4 @@ +kr.co.accura.wbx.spring.config.EmbeddedRedisConfig +kr.co.accura.wbx.spring.config.RedisCacheAutoConfig kr.co.accura.wbx.spring.config.WbxAutoConfiguration kr.co.accura.wbx.spring.admin.AdminAutoConfiguration diff --git a/wbx-spring-core/src/main/resources/application-example.yml b/wbx-spring-core/src/main/resources/application-example.yml index d3f6f67..0dda507 100644 --- a/wbx-spring-core/src/main/resources/application-example.yml +++ b/wbx-spring-core/src/main/resources/application-example.yml @@ -26,10 +26,11 @@ spring: minimum-idle: 5 connection-timeout: 30000 - data: - redis: - host: localhost - port: 6379 + # Redis (선택 — 미설정 시 인메모리 캐시 자동 사용) + # data: + # redis: + # host: localhost + # port: 6379 server: port: 8080 diff --git a/wbx-spring-core/src/main/resources/application-test.yml b/wbx-spring-core/src/main/resources/application-test.yml index 18cdd23..61f1f86 100644 --- a/wbx-spring-core/src/main/resources/application-test.yml +++ b/wbx-spring-core/src/main/resources/application-test.yml @@ -16,11 +16,6 @@ spring: flyway: enabled: false - data: - redis: - host: localhost - port: 6379 - wbx: spring: jwt: