M1 mac + SpringBoot + Embedded Redis + redisServer.start(); 시 에러 발생
에러 발생 코드
package com.express.freight.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.stereotype.Component;
import redis.embedded.RedisServer;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Configuration
@EnableRedisRepositories
@Component
public class RedisConfig {
private String host;
private int port;
private RedisServer redisServer;
public RedisConfig(@Value("${spring.redis.host}") String host,@Value("${spring.redis.port}") int port) {
this.host = host;
this.port = port;
}
@PostConstruct
public void startRedis() {
if (redisServer == null || !redisServer.isActive()) {
redisServer = new RedisServer(port);
redisServer.start();
}
}
}
에러 발생 로그
java.lang.RuntimeException: Can't start redis server. Check logs for details.
at redis.embedded.AbstractRedisInstance.awaitRedisServerReady(AbstractRedisInstance.java:62)
at redis.embedded.AbstractRedisInstance.start(AbstractRedisInstance.java:39)
at redis.embedded.RedisServer.start(RedisServer.java:9)
at com.express.freight.config.RedisConfig.startRedis(RedisConfig.java:39)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:440)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:921)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292)
at com.express.freight.FreightApplication.main(FreightApplication.java:12)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50)
원인
spring boot + Embedded Redis 가 Mac m1의 Arm 프로세서 아키텍처를 지원하지 않아서.
해결
1. 터미널에서 다음과 같이 작업한다.
wget(webget)이 없다면,
$ brew install wget
$ wget https://download.redis.io/releases/redis-6.2.5.tar.gz
$ tar xzf redis-6.2.5.tar.gz
$ cd redis-6.2.5
$ make
* 버전상의 이슈로 다운로드가 잘 안되거나 make 가 안될경우 :
https://redis.io/download/#redis-downloads
Download
Redis You can download the last Redis source files here. For additional options, see the Redis downloads section below. Stable (7.2) Redis 7.2 includes optimizations, several new commands, some improvements, bug fixes, and several new module APIs. It also
redis.io
공식 사이트에서 다운로드 - tar - make install (권한유의)
이후 src/redis-server 실행
2. 실행된 레디스 서버를 복사한다.
프로젝트에서 요렇게 해준다 (resources 하위에 위치)
와 같이 세팅하고,
3. RedisConfig.java 파일을 다음과 같이 작성한다.
package com.express.freight.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.stereotype.Component;
import redis.embedded.RedisServer;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;
import java.util.Objects;
@Configuration
@EnableRedisRepositories
@Component
public class RedisConfig {
private String host;
private int port;
private RedisServer redisServer;
public RedisConfig(@Value("${spring.redis.host}") String host,@Value("${spring.redis.port}") int port) {
this.host = host;
this.port = port;
}
@PostConstruct
public void startRedis() {
try {
if (redisServer == null || !redisServer.isActive()) {
redisServer = new RedisServer(Objects.requireNonNull(new ClassPathResource("/redis-server-mac-arm64").getFile()), port);
redisServer.start();
}
} catch ( Exception e) {
e.printStackTrace();
}
}
@PreDestroy
public void stopRedis() {
if (redisServer != null) {
redisServer.stop();
}
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
redisConfiguration.setHostName(this.host);
redisConfiguration.setPort(this.port);
redisConfiguration.setDatabase(0);
return new LettuceConnectionFactory(redisConfiguration);
}
@Bean(name = "redisTemplate")
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
}
실행 후 Redis가 잘 실행 되었는 지 체크한다.
Test API를 통해 Redis와의 통신도 잘 이루어 지는 지 체크한다.
참고용 : build.gradle
Spring boot / java 11 / query dsl / junit5 등 여러 설정이 섞여있습니다.
buildscript {
ext {
queryDslVersion = "5.0.0"
}
}
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.16-SNAPSHOT'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}
bootJar{
mainClass='com.express.freight.FreightApplication'
}
jar {
enabled = false
}
group = 'com.express'
version = '0.1'
java {
sourceCompatibility = '11'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
querydsl.extendsFrom compileClasspath
}
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.xerial:sqlite-jdbc:3.36.0.3'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// junit5
testImplementation("org.junit.platform:junit-platform-launcher:1.5.2")
testImplementation("org.junit.jupiter:junit-jupiter:5.5.2")
// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
// embedded redis ( h2 와 같은 내장 redis )
implementation("it.ozimov:embedded-redis:0.7.2")
// jwt
implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1'
// local test sqlite 3
implementation 'org.xerial:sqlite-jdbc:3.36.0.3'
// postgresql
implementation 'org.postgresql:postgresql'
// swagger ui 3
implementation group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0'
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '3.0.0'
compile group: 'io.swagger', name: 'swagger-annotations', version: '1.6.2'
compile group: 'io.swagger', name: 'swagger-models', version: '1.6.2'
// querydsl
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
//MapStruct
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
// mysql
implementation 'com.mysql:mysql-connector-j'
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4'
annotationProcessor(
"jakarta.persistence:jakarta.persistence-api",
"jakarta.annotation:jakarta.annotation-api",
)
}
// query dsl
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
library = "com.querydsl:querydsl-apt"
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main.java.srcDir querydslDir
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
querydsl.extendsFrom compileClasspath
}
compileQuerydsl{
options.annotationProcessorPath = configurations.querydsl
}