SpEL ??? 스펠?
- SpEL(Spring Expression Language)의 기본 개념
- @Cacheable, @CachePut, @CacheEvict에서 SpEL을 활용해 동적 키를 생성하는 법
- 메서드 파라미터, 리턴값, 객체 프로퍼티 등을 참조하는 표현식 작성
- 복합 키(Composite Key)를 구성하는 실무 예시
- 사용자 정의 함수를 SpEL 내에서 호출하는 법
SpEL(Spring Expression Language)
SpEL은 Spring에서 제공하는 표현식 언어(Expression Language)로,
런타임 시점에 동적으로 값을 계산하거나 프로퍼티, 메서드, 변수에 접근할 수 있는 기능들을 제공한다고 한다
Spring Cache에서는 SpEL을 활용하여 캐시 키를 동적으로 지정할 수 있다고 함
1. SpEL 문법의 기본 구조
SpEL은 #{} 또는 "#id" 같은 형태로 작성함
import com.b1uffer.cachetest.entity.User;
import com.b1uffer.cachetest.repository.UserRepository;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.NoSuchElementException;
@Service
public class UserService {
private UserRepository userRepository;
@Cacheable(value = "users", key = "#id")
public User findUser(Long id) {
User user = userRepository.findById(id).orElseThrow(() -> new NoSuchElementException("없음"));
return user;
}
}
| 요소 | 의미 |
| #id | 메서드 파라미터 id값을 참조함 |
| #root.args[0] | 첫번째 파라미터를 참조함 |
| #root.methodName | 메서드 이름을 참조함 |
| #result | 메서드 실행 결과를 참조함(메서드 실행 후에만 사용 가능함) |
2. SpEL이 사용 가능한 애너테이션 속성
SpEL은 애너테이션(@Cacheable, @CachePut, @CacheEvict 등) 속성에서 사용할 수 있음
- @Cacheable : key, condition, unless (key = "#user.id")
- @CachePut : key, condition (key = "#product.id")
- @CacheEvict : key, condition (key = "#id")
메서드 파라미터 참조하기
SpEL의 가장 기본적 사용법은 메서드의 파라미터를 캐시 키로 활용하는 것임
import com.b1uffer.cachetest.entity.User;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Cacheable(value = "userCache", key = "#userId")
public User getUserById(Long userId) {
System.out.println("DB 조회 발생");
User user = new User(userId, "블러퍼", 12);
return user;
}
}
* key = "#userId" 를 통해 메서드 파라미터 이름인 userId(Long userId)를 캐시 키로 활용함
* 동일한 userId 값으로 다시 호출하면, 캐시된 데이터가 반환된다
* SpEL의 다양한 파라미터 접근 방식
- #userId : 파라미터 이름으로 접근함
- #a0, #p0 : 첫번째 파라미터로 접근함
- #root.args[0] : 루트 객체의 첫번째 인자로 접근함
복합 키(Composite Key) 구성하기
복합 키는 여러 파라미터를 결합하여 고유한 캐시 키를 만드는 방법임
@Cacheable(value = "userCache", key = "#name + '_' + #id")
public User getUser(String name, Long id) {
User user = new User(id, name, 11);
return user;
}
* 이름과 ID를 결합하여 b1uffer_11, b1uffer_12와 같은 형태의 캐시 키를 생성해주는 복합 키 생성 방법임
응용 예시
import com.b1uffer.cachetest.entity.Order;
import com.b1uffer.cachetest.entity.User;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
@Cacheable(value = "orderCache", key = "#user.id + ':' + #order.id")
public Order getOrder(User user, Order order) {
// 로직
}
}
이 방식은 사용자별 주문 정보 캐시와 같이 다중 속성을 구분해야할 때 유용하다고 한다.
* getter 혹은 get 메서드가 있어야함
메서드 실행 결과(@Cacheable unless, @CachePut) 활용하기
#result를 활용하면 메서드 실행 후의 결과값을 조건으로 사용할 수 있다고 함
import com.b1uffer.cachetest.entity.User;
import com.b1uffer.cachetest.repository.UserRepository;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.NoSuchElementException;
@Service
public class UserService {
private UserRepository userRepository;
@Cacheable(value = "userCache", key = "#id", unless = "#result == null")
public User findUser(Long id) {
User user = userRepository.findById(id).orElseThrow(() -> new NoSuchElementException("없음"));
return user;
}
}
* unless는 결과가 null인 경우, 캐시를 저장하지 않도록 하는 속성임
* unless 안에 있는 #result는 반드시 메서드 실행 이후에만 접근 가능한 속성임
| 속성 | 의미 |
| condition | 메서드 실행 전, 캐시 저장 여부를 결정함 |
| unless | 메서드 실행 후, 결과값을 기반으로 캐시 저장 여부를 결정함 |
사용자 정의 함수 호출
SpEL은 Spring Bean에 등록된 메서드를 호출하여 캐시 키를 만들수도 있음
가령, KeyGeneratorUtil 클래스를 작성하여 사용자 정의 로직을 구현할 수도 있다고 함!
import org.springframework.stereotype.Component;
@Component("keyUtil")
public class KeyGeneratorUtil {
public String createKey(String prefix, Object id) {
return prefix + "_" + id;
}
}
이후에 SpEL에서 해당 메서드를 호출할 수 있음 (!!)
@Cacheable(value = "userCache", key = "@keyUtil.createKey('USER', #id)")
public User getUser(String name, Long id) {
User user = new User(id, name, 11);
return user;
}
key에서 @keyUtil이 보이는가? 우리가 @Component로 등록한 클래스 Bean이다. 오 마이 갓... 이게 되네
- @KeyUtil : Spring Bean의 이름을 참조한 것(@Component("keyUtil"))
- .createKey() : 메서드 호출
- 결과적으로 캐시 키는 USER_1, USER_2 와 같은 형태로 생성된다!
팁
* SpEL은 유연하지만, 복잡한 키 조합을 자주 사용하면 유지보수가 어려워 질 수 있으니 주의.
* 가독성이 떨어지는 경우 KeyGenerator 인터페이스를 구현하는 별도 클래스를 두는 것을 권장
* 캐시 키에는 절대 개인 정보(이메일, 비밀번호 등)을 포함하지 않기
* 문자열 결합( + + + + )이 많은 경우, String.format() 형태의 키 유틸을 사용하는게 안전하다고 함
정리
| 항목 | 설명 |
| #paramName | 메서드 파라미터를 참조함 |
| #root.args[n] | n번째 인자에 접근함 |
| #result | 메서드 실행 결과를 참조함 |
| @beanName.method() | Bean 메서드를 호출함 |
| condition, unless | 캐시 조건 제어 속성 |
'Spring Boot > Cache' 카테고리의 다른 글
| 로컬 캐시 구현과 최적화 : 로컬 캐시 구성 최적화 (0) | 2026.01.12 |
|---|---|
| 로컬 캐시 구현과 최적화 : 로컬 캐시 구현 옵션 (0) | 2026.01.12 |
| Spring Cache 기본 사용 : Spring Cache 활성화 및 주요 캐시 애너테이션 (0) | 2026.01.10 |
| Spring Cache 추상화 : Spring Boot 캐시 자동 설정 (0) | 2026.01.09 |
| Spring Cache 추상화 : 캐시 동작 원리 (0) | 2026.01.09 |