반응형
해당 글에서는 API Cache에 대해서 이해하고 REST API 환경에서 이를 적용하는 방법에 대해서 작성한 글입니다.
1) 개발환경 구성
💡 개발환경은 MyBatis를 기반으로 RDBMS로부터 전달받은 데이터를 캐시 처리하는 환경으로 구성하였습니다.
개발 환경 | 버전 |
java | 1.8 |
Spring Boot | 2.7.4 |
빌드관리도구 | Gradle 7.5 |
개발 툴 | IntelliJ IDEA 2022.3 |
spring-boot-starter-cache | 2.7.4 |
mybatis-spring-boot-starter | 2.2.2 |
[참고] 이전의 작성한 개발환경에 spring-boot-starter-cache를 추가하여 환경을 구성하였습니다.
2) API 캐싱, Spring Boot Cache 이해
💡 API Caching (캐싱)
- API의 호출에 따라서 캐시를 이용하여 '서버의 부하를 줄이고 API 성능을 최적화'하여 '응답시간을 단축'시키는 역할을 수행합니다.
💡Spring Boot Starter Cache
- 자주 사용되는 데이터를 ‘캐시’를 ‘메모리’에 저장하여 빠른 검색을 가능하게 하는 기능을 제공합니다.
- 해당 캐시에 저장되는 데이터를 CacheManager를 통하여 메모리뿐만 아니라 디스크, 데이터베이스, 클라우드 서비스와 같은 ‘다른 저장소’에도 저장이 가능합니다.
💡 [참고] API 캐시와 세션과 관련되어 작성한 글입니다.
1. Spring Boot Cache 사용 목적
💡 Spring Boot Cache 사용목적
- API에서 Database로부터 데이터를 조회하는 경우 ‘동일한 데이터를 반복하여 조회’ 해옴으로써 ‘불필요한 일을 반복하는 문제’가 발생합니다.
- 이에 따라서 API 캐시를 통해서 DB로부터 반복적으로 데이터를 조회해 오는 일에 대해 최초 데이터를 조회해 온 뒤 이후는 캐시에서 데이터를 조회해 오는 처리를 수행함으로써 API의 성능을 올리며 응답시간을 단축하는 효율성을 가져옵니다.
2. Spring Boot Cache 사용처
💡 Spring Boot Cache 사용처
- 해당 경우들에서 ‘자주 조회되는 데이터’에 대해서 캐시에 저장하여 성능향상을 기대할 수 있습니다. 이를 통해 외부 저장소에 대해서 부하 및 데이터베이스 등의 부하를 줄여서 서버의 성능을 개선하는데 도움이 됩니다.
- Spring Boot Cache의 사용처는 사용자의 로그인 정보(인증정보), 게시글 목록 등에 사용이 됩니다.
3) Spring Boot Cache Annotation
💡Spring Boot Cache Annotation
- Spring Boot Cache 라이브러리에서 사용되는 어노테이션 목록입니다.
1. Spring Boot Cache 어노테이션 설명
Annotation | 설명 |
@EnableCaching | Spring Boot Cache를 사용하기 위해 '캐시 활성화'를 위한 어노테이션을 의미합니다. |
@CacheConfig | 캐시정보를 '클래스 단위'로 사용하고 관리하기 위한 어노테이션을 의미합니다. |
@Cacheable | 캐시정보를 메모리 상에 ‘저장’하거나 ‘조회’ 해오는 기능을 수행하는 어노테이션입니다. |
@CachePut | 캐시 정보를 메모리상에 '저장'하며 존재 시 갱신하는 기능을 수행하는 어노테이션입니다. |
@CacheEvict | 캐시 정보를 메모리상에 '삭제'하는 기능을 수행하는 어노테이션입니다. |
@Caching | 여러 개의 ‘캐시 어노테이션’을 ‘함께 사용’할 때 사용하는 어노테이션입니다. |
2. 주요 Annotation 비교하며 이해하기
💡 Spring Boot Cache에서는 아래의 주요한 어노테이션을 사용합니다.
어노테이션 | 주요 기능 | 캐싱 실행 시점 |
@Cacheable | 캐시 조회, 저장 기능 | - 캐시 존재 시 ‘메서드 호출 전 실행’ - 캐시 미 존재 시 ‘메서드 호출 후 실행’ |
@CachePut | 캐시 저장 기능 | - 캐시 존재 시 ‘메서드 호출 후 실행’ - 캐시 미 존재 시 ‘메서드 호출 후 실행’ |
@CacheEvict | 캐시 삭제 기능 | - beforeInvocation 속성값이 true일때 ‘메서드 호출 전 실행’ - beforeInvocation 속성값이 false일때 ‘메서드 호출 후 실행’ |
[ 더 알아보기 ]
💡 메서드의 호출 전/후 실행은 무슨 차이일까?
- 메서드의 호출 전에 실행 시 DB로부터 데이터를 처리하는 부분에 대해서 줄어들게 됩니다.
- 반대로 메서드의 호출 후에 실행하는 경우 DB로부터 데이터를 처리하여 가져오는 부분에 대해서 처리하는 부분이 늘어납니다.
💡 @CacheEvict의 beforeInvocation 속성이란?
- 캐시의 데이터를 삭제하는데 메서드 호출 전/후에 발생할지에 대해 설정하는 속성을 의미합니다.
- 속성의 기본값은 false이며 메서드 실행 전에 캐시에서 데이터를 삭제하여 예외가 발생한다면 캐시에서 데이터가 삭제되지 않습니다.
- 이에 따라 예외가 발생할 가능성이 있는 메서드에 대해서 beforeInvocation= “true”를 사용하지 않는 것이 좋습니다.
💡 @Cacheable과 @CachePut의 다른 점은?
- @Cacheable의 경우는 ‘캐시가 존재하지 않을 경우’ 캐시를 저장하지만 @CachePut의 경우는 ‘캐시의 존재 여부를 떠나서’ 항상 저장 혹은 갱신을 수행합니다.
1. @EnableCaching
💡 @EnableCaching
- Spring Boot Cache를 사용하기 위해 '캐시 활성화'를 위해 사용됩니다.
- 해당 어노테이션의 선언 위치는 CacheManager()를 구현한 @Configuration부분에서 선언하여 사용합니다.
💡 @EnableCaching 속성 값
속성 | 속성 기본 값 | 설명 |
value | 빈 이름 | 캐시 매니저 이름을 지정한다. |
order | Ordered.LOWEST_PRECEDENCE | 캐시 관련 빈들의 우선순위를 지정한다. |
keyGenerator | - | 캐시에서 사용할 키 생성기를 지정한다. |
cacheManager | - | 사용할 캐시 매니저를 직접 지정한다. |
cacheResolver | - | 사용할 캐시 리졸버를 직접 지정한다. |
proxyTargetClass | false | 프록시를 생성할 때 CGLIB를 사용할지, 아니면 JDK Dynamic Proxy를 사용할지 결정한다. |
💡 CacheManager의 종류
CacheManager | 캐시 저장 위치 | 설명 |
ConcurrentMapCacheManager | 메모리 상에 캐시 저장 | ConcurrentHashMap 기반 캐시 구현체를 의미합니다. |
CaffeineCacheManager | 메모리 상에 캐시 저장 | Caffeine 기반 캐시 구현체 |
SimpleCacheManager | 메모리 상에 캐시 저장 | 단순 캐시 구현체를 의미합니다. |
EhCacheCacheManager | 디스크 또는 데이터베이스에 저장 | Ehcache 기반 캐시 구현체를 의미합니다. |
HazelcastCacheManager | 메모리 상에 캐시 저장 | Hazelcast 기반 캐시 구현체를 의미합니다. |
InfinispanCacheManager | 메모리 상에 캐시 저장 | Infinispan 기반 캐시 구현체를 의미합니다. |
RedisCacheManager | Redis 내의 데이터베이스에 저장 | Redis 기반 캐시 구현체를 의미합니다. |
CouchbaseCacheManager | Couchbase 내의 데이터베이스에 저장 | Couchbase 기반 캐시 구현체를 의미합니다. |
GemfireCacheManager | 자체 저장소에 저장 | GemFire 기반 캐시 구현체를 의미합니다. |
CoherenceCacheManager | 자체 저장소에 저장 | Oracle Coherence 기반 캐시 구현체를 의미합니다. |
💡 예시 설명
- 해당 CacheConfig라는 클래스는 Config 파일입니다.
1. @EnableCaching을 선언하여 Spring Boot Cache를 사용함을 선언하였고, @Bean을 이용하여서 CacheManager를 구성하였습니다.
2. CacheManager에서는 ConcurrentMapCacheManager를 사용하고 “codeCache”를 메모리상에 등록하고 사용하도록 구성하였습니다.
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
log.debug("[+] CacheConfig Start !!! ");
// "codeCacheInfo"라는 캐시를 관리합니다.
return new ConcurrentMapCacheManager("codeCache");
}
}
2. @CacheConfig
💡 @CacheConfig
- 캐시를 '클래스 단위'로 '사용하고 관리'하기 위해 사용됩니다.
- 이를 사용하면 ‘클래스 단위로 관리’를 하면 동일한 이름의 캐시를 반복하여 입력할 필요를 줄여줍니다.
- 해당 어노테이션의 선언 위치는 캐시를 사용하는 @Service 부분에서 선언하여 사용합니다.
💡@EnableCaching 속성
속성 | 설명 |
cacheNames | 캐시할 데이터의 이름을 지정합니다. |
cacheManager | 캐시 매니저의 이름을 지정합니다. |
cacheResolver | 캐시 리졸버의 이름을 지정합니다. |
keyGenerator | 캐시 키 생성기의 이름을 지정합니다. |
cacheManagerCustomizers | 캐시 매니저 커스터마이저의 이름을 지정합니다. |
key | 캐시할 데이터에서 사용할 키를 지정합니다. |
condition | 캐시를 적용할 조건을 지정합니다. |
unless | 캐시 적용을 제외할 조건을 지정합니다. |
sync | 캐시 동기화 여부를 지정합니다. |
beforeInvocation | 메서드 실행 전에 캐시를 적용할지 여부를 지정합니다. |
💡 예시 설명
- 해당 CodeServiceImpl라는 클래스는 CodeService의 인터페이스의 구현체로 사용되는 파일입니다.
1. @CacheConfig(cacheNames = "code")라는 속성으로 클래스 내부에서 “code”라는 값으로 공통적으로 사용하도록 구성하였습니다.
@Service
@CacheConfig(cacheNames = "code")
public class CodeServiceImpl implements CodeService {
...
}
3. @Cacheable
💡 @Cacheable
- 캐시 정보를 메모리 상에 '저장'하거나 '조회' 해오는 기능을 수행할 때 사용됩니다.
- 상세한 설명으로는 캐시의 속성값인 '값(value)과 키(key)'를 기반으로 수행이 됩니다.
- 최초 호출이 된 경우에는 메서드가 호출되어 '캐시 정보를 저장' 하며, 동일하게 재 호출이 된 경우에는 메서드의 호출 없이 '저장된 캐시의 정보를 조회하여 반환'합니다.
- @CachePut 어노테이션과 비슷한 기능을 수행하지만 '캐시 정보를 조회'하는데 주로 사용합니다.
- 해당 어노테이션의 선언 위치는 주로 @Service를 선언한 인터페이스의 구현체 부분에서 함께 선언하여 사용합니다.
💡 @Cacheable 속성
속성 | 설명 |
value | 캐시로 사용될 이름을 지정합니다. |
key | 캐시의 key로 사용될 SpEL 표현식을 이용하여 지정합니다. |
condition | 캐시를 저장할 조건을 지정하는 SpEL 표현식을 이용하여 지정합니다. |
unless | 캐시를 저장하지 않을 조건을 지정하는 SpEL 표현식을 이용하여 지정합니다. |
cacheManager | 사용할 캐시 매니저를 지정하는데 사용될 캐시 매니저의 이름을 지정합니다. |
cacheResolver | 사용할 캐시 해결자 빈을 지정하는데 사용될 캐시 해결자 빈 이름을 지정합니다. |
💡 예시 설명
- 해당 selectCodeList()의 메서드는 CodeServiceImpl라는 클래스는 CodeService의 인터페이스의 구현체로 사용되는 클래스 파일에 포함된 함수입니다.
1. @Cacheable(value = "codeCacheInfo", key = "#codeDto.grpCd")를 통해서 해당 메서드의 호출을 하는 경우 codeCacheInfo의 캐시의 값에 객체로 전달받은 codeDto.grpCd 값에 따라서 해당 캐시가 저장이 됩니다.
2. 동일한 값과 키값을 통해서 메서드의 호출이 발생하는 경우 메서드를 호출하지 않고 캐시에서 데이터를 가져와서 결과값을 반환해 줍니다.
@Service
public class CodeServiceImpl implements CodeService {
/**
* 코드 리스트를 조회합니다.
*
* @param codeDto CodeDto
* @return List<CodeDto>
*/
@Transactional(readOnly = true)
@Cacheable(value = "codeCacheInfo", key = "#codeDto.grpCd")
public List<CodeDto> selectCodeList(CodeDto codeDto) {
CodeMapper cm = sqlSession.getMapper(CodeMapper.class);
return cm.selectCodeList(codeDto);
}
}
4. @CachePut
💡 @CachePut
- 캐시 정보를 메모리상에 '저장'하며 존재 시 갱신하는 기능을 수행할 때 사용합니다.
- 상세한 설명으로는 캐시의 속성값인 '값(value)과 키(key)'를 기반으로 수행이 됩니다.
- 최초 호출이 된 경우에는 메서드가 호출되어 ‘캐시 정보를 저장’하며, 동일하게 재 호출이 된 경우에도 메서드가 호출되어 ‘캐시 정보를 갱신(수정 및 저장)’하여 캐시의 정보를 반환합니다.
- @Cacheable 어노테이션과 비슷한 기능을 수행하지만 '캐시 정보를 저장'하는데 주로 사용이 됩니다.
- 해당 어노테이션의 선언 위치는 주로 @Service를 선언한 인터페이스의 구현체 부분에서 함께 선언하여 사용합니다.
💡 @CachePut 속성
속성 | 설명 |
value | 캐시 이름을 지정합니다. |
key | 캐시에 저장할 때 사용할 키를 지정한다. SpEL 표현식으로 작성 가능합니다 |
condition | 캐시에 저장할 조건을 지정한다. SpEL 표현식으로 작성 가능하며, 조건이 false 일 경우 캐시 저장을 하지 않습니다 |
unless | 캐시에 저장하지 않을 조건을 지정한다. condition과 반대로 동작하며, SpEL 표현식으로 작성 가능합니다 |
keyGenerator | 캐시에 사용할 키 생성기를 지정합니다 |
cacheManager | 캐시 매니저를 지정합니다. |
💡 예시 설명
- 해당 selectCodeByCd()의 메서드는 CodeServiceImpl라는 클래스는 CodeService의 인터페이스의 구현체로 사용되는 클래스 파일에 포함된 함수입니다.
1. @CachePut(value = "codeCacheInfo", key = "#cd")를 통해서 해당 메서드의 호출을 하는 경우 codeCacheInfo의 캐시의 값에 파라미터로 전달받은 cd 값에 따라서 해당 캐시가 저장이 됩니다.
2. 동일한 값과 키를 통해서 메서드의 호출이 발생하더라도 메서드는 호출되어 해당 캐시를 갱신하여 결과값을 반환해 줍니다.
@Service
public class CodeServiceImpl implements CodeService {
/**
* 코드 키 값을 기반으로 코드 정보를 조회합니다
*
* @param cd String
* @return CodeDto
*/
@Transactional(readOnly = true)
@CachePut(value = "codeCacheInfo", key = "#cd")
public CodeDto selectCodeByCd(String cd) {
CodeMapper cm = sqlSession.getMapper(CodeMapper.class);
return cm.selectCodeByCd(cd);
}
}
5. @CacheEvict
💡 @CacheEvict
- 캐시 정보를 메모리상에 '삭제'하는 기능을 수행할 때 사용합니다.
- 상세한 설명으로는 캐시는 속성값인 '값(value)과 키(key)'를 기반으로 수행이 됩니다.
- 어노테이션의 속성인 beforeInvocation의 값이 true이면 '메서드 호출 전'에 실행이 되며, false이면 '메서의 호출 후에 실행'이 됩니다.
- 해당 어노테이션의 선언 위치는 주로 @Service를 선언한 인터페이스의 구현체 부분에서 함께 선언하여 사용합니다.
💡 @CacheEvict 속성 값
속성 | 설명 |
value | 캐시 이름을 지정합니다 |
key | 캐시에서 삭제할 키 값을 지정합니다. |
condition | 캐시 삭제 조건. SpEL 표현식 사용 가능합니다 |
allEntries | 전체 캐시 삭제 여부입니다 |
beforeInvocation | 메소드 실행 전 캐시 삭제 여부입니다 |
[ 예시 설명 ]
- 해당 deleteCode()의 메서드는 CodeServiceImpl라는 클래스는 CodeService의 인터페이스의 구현체로 사용되는 클래스 파일에 포함된 함수입니다.
1. @CacheEvict(value = "codeCacheInfo", key = "#codeDto.grpCd", beforeInvocation = false)를 통해서 해당 메서드의 호출을 하는 경우 codeCacheInfo의 캐시 값과 codeDto.grpCd의 키 값에 따라서 캐시를 삭제합니다.
2. beforeInvocation 속성을 false로 지정하였기에 메서드가 실행된 이후에 캐시를 삭제하도록 처리하였습니다.
@Service
public class CodeServiceImpl implements CodeService {
/**
* 코드 삭제
*
* @param codeDto CodeDto
* @return int
*/
@Transactional
@CacheEvict(value = "codeCacheInfo", key = "#codeDto.grpCd", beforeInvocation = false)
public int deleteCode(CodeDto codeDto) {
CodeMapper cm = sqlSession.getMapper(CodeMapper.class);
try {
return cm.deleteCode(codeDto);
} catch (Exception e) {
throw new BusinessExceptionHandler(e.getMessage(), ErrorCode.INSERT_ERROR);
}
}
}
6. @Caching
💡 @Caching이란?
- 여러 개의 '캐시 어노테이션을 함께 사용할 때 사용'됩니다.
- 예를 들어, @CachePut과 @CacheEvict를 함께 사용할 때 사용됩니다.
[참고] @Caching의 속성 값
속성 | 설명 |
cacheable | 캐시 정보를 조회하는데 사용하는 @Cacheable 어노테이션을 단일 혹은 다중으로 사용할 수 있도록 하는 속성입니다. |
put | 캐시 정보를 저장하는데 사용하는 @CachePut 어노테이션을 단일 혹은 다중으로 사용할 수 있도록 하는 속성입니다. |
evict | 캐시 정보를 삭제하는데 사용하는 @CacheEvict 어노테이션을 단일 혹은 다중으로 사용할 수 있도록 하는 속성입니다. |
[ 예시 설명 ]
- 해당 selectCodeList()의 메서드는 CodeServiceImpl라는 클래스는 CodeService의 인터페이스의 구현체로 사용되는 클래스 파일에 포함된 함수입니다.
- @Caching 어노테이션을 이용하여 조회를 수행하는 cacheable 속성과 수정을 수행하는 put 속성을 함께 사용하도록 구성하였습니다.
- 메서드를 호출하는 경우 조회와 생성이 함께 수행이 되도록 구성하였습니다.
/**
* 코드 리스트를 조회합니다.
*
* @param codeDto CodeDto
* @return List<CodeDto>
*/
@Transactional(readOnly = true)
@Caching(
cacheable = {
@Cacheable(value = "codeCacheInfo", key = "#codeDto.grpCd")
},
put = {
@CachePut(value = "codeCacheInfo", key = "#codeDto.grpCd"),
}
)
public List<CodeDto> selectCodeList(CodeDto codeDto) {
CodeMapper cm = sqlSession.getMapper(CodeMapper.class);
return cm.selectCodeList(codeDto);
}
3) Spring Boot Cache 설정하기
1. 라이브러리 추가합니다.
💡 build.gradle 파일 내에 ‘spring-boot-starter-cache' 라이브러리의 의존성을 추가합니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-cache'
}
💡 [참고] Maven Repository : spring-boot-starter-cache
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-cache
2. CacheManager 설정합니다.
💡 CacheManager
- 캐시를 관리하고 캐시 된 ‘데이터를 저장’하고 ‘반환’하는 역할을 합니다.
- 일반적으로 메모리 상에 저장되는 데이터를 디스크, 데이터베이스, 클라우드 서비스와 같은 저장소에 저장이 가능하도록 합니다.
- 해당 캐시는 Redis, Ehcache, Caffeine 등 다양한 캐시 라이브러리와 연동하여 사용할 수 있습니다.
💡 CacheManager의 종류
CacheManager | 캐시 저장 위치 | 설명 |
ConcurrentMapCacheManager | 메모리 상에 캐시 저장 | ConcurrentHashMap 기반 캐시 구현체를 의미합니다. |
CaffeineCacheManager | 메모리 상에 캐시 저장 | Caffeine 기반 캐시 구현체 |
SimpleCacheManager | 메모리 상에 캐시 저장 | 단순 캐시 구현체를 의미합니다. |
EhCacheCacheManager | 디스크 또는 데이터베이스에 저장 | Ehcache 기반 캐시 구현체를 의미합니다. |
HazelcastCacheManager | 메모리 상에 캐시 저장 | Hazelcast 기반 캐시 구현체를 의미합니다. |
InfinispanCacheManager | 메모리 상에 캐시 저장 | Infinispan 기반 캐시 구현체를 의미합니다. |
RedisCacheManager | Redis 내의 데이터베이스에 저장 | Redis 기반 캐시 구현체를 의미합니다. |
CouchbaseCacheManager | Couchbase 내의 데이터베이스에 저장 | Couchbase 기반 캐시 구현체를 의미합니다. |
GemfireCacheManager | 자체 저장소에 저장 | GemFire 기반 캐시 구현체를 의미합니다. |
CoherenceCacheManager | 자체 저장소에 저장 | Oracle Coherence 기반 캐시 구현체를 의미합니다. |
[ 더 알아보기 ]
💡 로컬 캐시(Local Cache)
- 캐시를 사용하는 한 개의 서버에서만 유효한 캐시입니다. 이는 서버의 메모리에 저장되며 서버가 재시작되거나 캐시가 만료될 때까지 유지됩니다.
💡 글로벌 캐시 (Globacl Cache)
- 여러 서버에서 공유하는 캐시입니다. 이를 위해서는 분산 캐시 기술이 필요하며 대표적인 기술로는 Redis, Memcached, Hazelcast 등이 있습니다.
- 글로벌 캐시를 사용하면 여러 서버에서 공유하는 캐시를 이용하여 성능을 향상할 수 있습니다.
💡 해당 예시에서는 @EnableCaching을 통해서 Spring Boot Cache를 사용함을 선언하였고 CacheManager인 ConcurrentMapCacheManager를 통해서 캐시를 관리합니다.
💡@EnableCaching 란?
- 캐시를 사용하기 위해 필요한 어노테이션으로 Spring Boot 애플리케이션에서 캐싱을 활성화하는 데 사용되며 @Configuration이 포함된 클래스에서 이를 적용합니다.
package com.adjh.multiflexapi.config;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 'ConcurrentMapCacheManager'를 통해서 캐시를 관리합니다.
*
* @author : lee
* @fileName : CacheConfig
* @since : 2023/03/28
*/
// 해당 Annotation을 추가합니다.
@EnableCaching
@Configuration
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("codeCacheInfo");
}
}
💡 CacheManager의 등록된 캐시가 아닐 경우 처리과정
- 아래와 같이 CacheManager에는 “codeCacheInfo”라는 캐시만 관리하게 저장한 상태고 code 캐시를 사용함을 지정하였습니다
/**
* 코드 키 값을 기반으로 코드 정보를 조회합니다
*
* @param cd String
* @return CodeDto
*/
@Cacheable(value = "code", key = "#cd")
public CodeDto selectCodeByCd(String cd) {
CodeMapper cm = sqlSession.getMapper(CodeMapper.class);
return cm.selectCodeByCd(cd);
}
💡 등록된 캐시가 아닌 경우, 아래와 같은 오류가 발생하고 있습니다.
[참고] Sprng Boot Reference
https://www.baeldung.com/spring-cache-tutorial
💡 해당 글은 다음글에서 이어집니다.
오늘도 감사합니다. 😀
반응형
'Java > Spring Boot' 카테고리의 다른 글
[Java] Spring Boot Batch 이해하고 설정하기 -1 : 정의 및 이해 (2) | 2023.04.22 |
---|---|
[Java] Spring Boot Cache 이해하고 설정하기 -2 : 사용 및 활용 예시 (0) | 2023.04.16 |
[Java] Spring Boot AOP(Aspect-Oriented Programming) 이해하고 설정하기 (2) | 2023.03.01 |
[Java] Spring Boot Tomcat Access Log 이해하고 설정하기 (0) | 2023.02.26 |
[Java] Spring Boot Security 이해하기 -4: JWT 환경 설정 및 구성 하기 (4) | 2023.01.01 |