Cache๋ ์์ฃผ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ์ ์ฅํด๋๊ณ ๋ค์ ์ด ๋ฐ์ดํฐ๋ฅผ ํ์๋ก ํ ๋๋ง๋ค ๋น ๋ฅด๊ฒ ์ฐธ์กฐํ์ฌ ์ฝ๊ธฐ ๊ธฐ๋ฅ์ ๊ฐ์ ํ๋ ๊ธฐ์ ์ด๋ค.
ํ์ฌ ์งํ ์ค์ธ ํ๋ก์ ํธ์์ ์ฑ๋ฅ ๊ฐ์ ์ ์ํด ์บ์๋ฅผ ๋์ ํ์๊ณ , Redis๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ํ๋ค.
๊ฑฐ์ ๋ชจ๋ API ์์ฒญ์์ ํ์์ ์กฐํํ๋ ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ๊ณ ์ด๋ฅผ ์บ์ฑ์ฒ๋ฆฌํ๊ธฐ ์ํด ์์ ๊ฐ์ด ๊ตฌ์ํ์๋ค.
์ต์ด ๋ก๊ทธ์ธ ์ redis์ ๊ฐ์ ๋ฃ์ด์ฃผ๊ณ ์ถํ์ loadByUsername ํธ์ถ๋ ๋ redis ์์ ๊ฐ์ ๋จผ์ ์ฐพ์ ์ ์๋๋ก ์ฝ๋๋ฅผ ์์ ํ์๋ค.
Redis ์ค์
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
RedisConfig
@Configuration
@EnableRedisRepositories
@RequiredArgsConstructor
public class RedisConfiguration {
/**
* redis ์ปค๋งจ๋๋ค์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ํ๊ธฐ ์ํ ํด๋์ค
*/
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
private final RedisProperties redisProperties;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
@Bean
public RedisTemplate<String, User> userRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, User> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory); // redis ์๋ฒ์ ๋ํ ์ ๋ณด๋ฅผ ๊ฐ๊ณ ์์
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<User>(User.class));
return redisTemplate;
}
}
Redis Repository
- expired ํ์์ ๊ฑธ์ด์ฃผ๋๊ฑธ ๊ถ์ฅ
@Repository
@RequiredArgsConstructor
@Slf4j
public class UserCacheRepository {
private final RedisTemplate<String, User> userRedisTemplate;
private final static Duration USER_CACHE_TTL = Duration.ofDays(3); // 3์ผ์ ๋ง๋ฃ๊ธฐ๊ฐ ์ธํ
public void setUser(User user) {
log.info("Set User to Redis {}:{}", getUser(user.getUsername()), user, USER_CACHE_TTL);
userRedisTemplate.opsForValue().set(getKey(user.getUsername()), user, USER_CACHE_TTL);
}
public User getUser(String userName) {
User user = userRedisTemplate.opsForValue().get(getKey(userName));
log.info("Get User to Redis {}:{}", getUser(userName), user);
return user;
}
//key ๊ฐ์ ํ๋ฆฌํฝ์ค๋ฅผ ๋ถ์ฌ์ค
private String getKey(String userName) {
return "USER:" + userName;
}
}
loadUserByUsername ๋ฐ login ๋ก์ง ์์
@Override
public User loadUserByUsername(String userName) throws UsernameNotFoundException {
// redis ์ ์๋์ง ์ฒดํฌํ๊ณ ์๋ค๋ฉด orElseGet ์ ์ฌ์ฉํ์ฌ db ์์ ์กฐํ
User user = userCacheRepository.getUser(userName)
.orElseGet(() -> userRepository.findByUserName(userName).map(User::fromEntity).orElseThrow(
() -> new SimpleSnsApplicationException(ErrorCode.USER_NOT_FOUND, String.format("userName is %s", userName))));
return user;
}
public String login(String userName, String password) {
User savedUser = loadUserByUsername(userName);
System.out.println("===================");
userCacheRepository.setUser(savedUser);
//๋น๋ฐ๋ฒํธ ์ฒดํฌ
if (!encoder.matches(password, savedUser.getPassword())) {
throw new SimpleSnsApplicationException(ErrorCode.INVALID_PASSWORD, String.format("userName is %s", userName));
}
return JwtTokenUtils.generateAccessToken(userName, secretKey, expiredTimeMs);
}