feat: Embedded Redis 적용 — Docker 없이 Redis 자동 구동
- EmbeddedRedisConfig: 외부 Redis 없으면 Embedded Redis 자동 시작 - RedisCacheAutoConfig: Redis 연결 실패 시 인메모리 캐시 fallback - install.bat/sh: Docker/Redis 필수 의존성 제거, 인메모리 전환 안내 - application yml: Redis 설정을 선택 사항으로 변경 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
이 Commit은 다음에 포함되어 있습니다:
@@ -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'
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -16,11 +16,6 @@ spring:
|
||||
flyway:
|
||||
enabled: false
|
||||
|
||||
data:
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
|
||||
wbx:
|
||||
spring:
|
||||
jwt:
|
||||
|
||||
새 Issue에서 참조
사용자 차단