Spring AOP, Cache - low-hill/Knowledge GitHub Wiki
ํต์ฌ์ ์ธ ๊ธฐ๋ฅ์์ ๋ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ์ ๋ถ๋ฆฌํ๋ค. ๋ถ๋ฆฌํ ๋ถ๊ฐ๊ธฐ๋ฅ์ Aspect๋ผ๋ ๋ชจ๋ ํํ๋ก ๋ง๋ค์ด์ ์ค๊ณํ๊ณ ๊ฐ๋ฐํ๋ ๋ฐฉ๋ฒ
Aspect: ๋ถ๊ฐ๊ธฐ๋ฅ์ ๋ด๊ณ ์๋ ๊ฐ์ฒด
Advise: ์ค์ง์ ์ธ ๋ถ๊ฐ๊ธฐ๋ฅ์ ๋ด์ ๊ตฌํ์ฒด, Aspect๋ '๋ฌด์'์ '์ธ์ ' ํ ์ง๋ฅผ ์ ์
@Around, @Before, @After, @AfterReturning, @AfterThrowing PointCut: ๋ถ๊ฐ ๊ธฐ๋ฅ์ด ์ ์ฉ๋์ด์ผ ํ ๋์(๋ฉ์๋)์ ์ ์ ํ๋ ๋ฐฉ๋ฒ
execution(), @annotion, ๋ฑ๋ฑ execution(๋ฆฌํด ํ์ ํ๊ฒ์ด ๋๋ ๋ฉ์๋ argument-๋งค๊ฐ๋ณ์) ex) execution(* com.dashboard.service.DashboardService(..)) JointPoint: Advise๊ฐ ์ ์ฉ๋ ์์น, controller์์ ์ ์๋ method๋ค์ args(๋งค๊ฐ๋ณ์)๋ฅผ ๋ด๊ณ ์๋ ๊ฐ์ฒด
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@Aspect
public class UserAuthAspect {
private static final Logger logger = LoggerFactory.getLogger(AccountAuthAspect.class);
@Autowired
private UserAuthService userAuthService;
@Pointcut("execution(* com.demo.dashboard.service.DashboardService.getBoard(..))")
public void dashBoardAccountAuth() {}
@Pointcut("execution(* com.demo.billing.service.BillingService.*(..))")
public void billingAccountAuth() {}
@Before("dashBoardAccountAuth() || billingAccountAuth()")
public void before(JoinPoint joinPoint) {
Object[] obj = joinPoint.getArgs();
CommonReqModel model = (CommonReqModel) obj[0];
boolean hasDefaultAuth = userAuthService.getAuthInfo(model);
model.setHasDefaultAuth(hasDefaultAuth);
}
}
ํต์ฌ๋ถ๋ถ์์ ์ถ์ํ๋ Java method์ ์บ์ฑ์ ์ ์ฉํจ์ผ๋ก์จ ์บ์์ ๋ณด๊ด๋ ์ ๋ณด๋ก ๋ฉ์๋์ ์คํ ํ์๋ฅผ ์ค์ฌ์ค๋ค. ์ฆ ๋์ ๋ฉ์๋๊ฐ ์คํ๋ ๋๋ง๋ค ์ถ์ํ๊ฐ ํด๋น ๋ฉ์๋๊ฐ ๊ฐ์ ์ธ์๋ก ์ด๋ฏธ ์คํ๋์๋ ํ์ธํ๋ ์บ์ฑ ๋์์ ์ ์ฉํ๋ค. ํด๋น ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ๋ค๋ฉด ๋ฉ์๋๋ฅผ ์คํํ์ง ์๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๊ณ ์กด์ฌํ์ง ์๋๋ค๋ฉด ๋ฉ์๋๋ฅผ ์คํํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํ ๋ค์ ์ฌ์ฉ์์๊ฒ ๋ฐํํด์ ๋ค์๋ฒ ํธ์ถ์์ ์ฌ์ฉ ํ ์ ์๊ฒ ํ๋ค.
Spring cache๋ cache ์ถ์ํ๋ฅผ ์ง์ํ๋๋ฐ EhCache, Redis, Couchbase ๋ฑ ์บ์ ์ ์ฅ์์ ๋น ๋ฅด๊ฒ ์ฐ๋ํ์ฌ bean์ผ๋ก ์ค์ ํ ์ ์๋๋ก ๋์์ค๋ค.
@Cacheable ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ๋ฉ์๋์ ๊ฒฐ๊ณผ๋ฅผ ์บ์ํฉ๋๋ค. ์ด ๋ฐฉ์์ ๋ฐ๋ณต์ ์ธ ์์ฒญ์ ๋ํด ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋๋ก ํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ ํธ์ถ์ ์ค์ ๋๋ค.
@Cacheable(value = "userCache", key = "#userId")
public User getUserById(Long userId) {
return userRepository.findById(userId);
}
Redis๋ ๋น ๋ฅธ ์ฝ๊ธฐ ์ฑ๋ฅ์ ์ ๊ณตํ๋ In-memory ๋ฐ์ดํฐ ์ ์ฅ์๋ก, ์์ฃผ ์กฐํ๋๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ์ ์ ํฉํฉ๋๋ค. Spring Boot์์๋ Spring Data Redis๋ฅผ ํตํด Redis์์ ์ฐ๋์ด ๊ฐ๋ฅํฉ๋๋ค. Redis๋ฅผ ์ฌ์ฉํ๋ฉด, ์์ฃผ ์กฐํ๋๋ ๋ฐ์ดํฐ๊ฐ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ๋์ด ๋น ๋ฅด๊ฒ ์๋ต์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. ์บ์ ๋ง๋ฃ ๊ธฐ๊ฐ(1์๊ฐ)์ ์ค์ ํ์ฌ ๋ฐ์ดํฐ๊ฐ ์ค๋๋ ๊ฒฝ์ฐ์๋ ์๋์ผ๋ก ๊ฐฑ์ ๋ ์ ์๋๋ก ํฉ๋๋ค.
- value
- ์บ์ฑ ๊ณต๊ฐ์ ๋ํ ๋ช ์นญ
- key
- Spring Expression Language(SpEl)์ผ๋ก key์์ฑ์ ์ง์
- ์ง์ ํ์ง ์์ผ๋ฉด ๋ชจ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ์กฐํฉํ ํด์์ฝ๋ ๊ฐ์ ํค๋ก ์์ฑ
- condition
- ์กฐ๊ฑด๋ถ ์บ์ฑ. SpEL๋ก ์ง์ ํ๊ณ ํํ์์ด true๋ฉด ๋ฉ์๋๋ฅผ ์บ์
์ด๋ฆ | ์์น | ์ค๋ช | ์์ |
---|---|---|---|
methodName | root object | ํธ์ถ๋๋ ๋ฉ์๋์ ์ด๋ฆ | #root.methodName |
method | root object | ํธ์ถ๋๋ ๋ฉ์๋ | #root.method.name |
target | root object | ํธ์ถ๋๋ ๋์ ๊ฐ์ฒด | #root.target |
targetClass | root object | ํธ์ถ๋๋ ๋์ ํด๋์ค | #root.targetClass |
args | root object | ๋์์ ํธ์ถํ๋๋ฐ ์ฌ์ฉํ ์ธ์(๋ฐฐ์ด) | #root.args[0] |
caches | root object | ํ์ฌ ์คํ๋ ๋ฉ์๋ ์บ์์ ์ปฌ๋ ์ | #root.caches[0].name |
argument name | evaluation context | ๋ฉ์๋ ์ธ์์ ์ด๋ฆ. ์ด๋ค ์ด์ ๋ก๋ ์ด๋ฆ์ ์ฌ์ฉํ ์ ์๋ค๋ฉด(์: ๋๋ฒ๊น ์ ๋ณด๊ฐ ์๋ ๊ฒฝ์ฐ) a<#arg>์์ ์ธ์ ์ด๋ฆ์ ์ฌ์ฉํ ์๋ ์๊ณ #arg์ (0๋ถํฐ ์์ํ๋) ์ธ์์ ์ธ๋ฑ์ค๋ฅผ ์๋ฏธํ๋ค. | iban๋ a0 (p0๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ๋ณ์นญ์ผ๋ก p<#arg> ํ์์ ์ฌ์ฉํ ์ ์๋ค) |
์ ์ํด์ผ ํ ์
@Cacheable์ Spring AOP๋ฅผ ์ด์ฉํ๊ธฐ ๋๋ฌธ์ ๋์ผํ ํด๋์ค ๋ด @Cacheable์ด ์ค์ ๋ ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฒฝ์ฐ ์บ์ฑ๋ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ค์ง ๋ชปํ๊ณ ๋ฉ์๋๋ฅผ ์ฌ์คํ ํ๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ internal call์ด ์๋ Proxy Bean๋ฅผ ์ฐธ์กฐํ์ฌ ์บ์ฑ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ์ค๋ ๊ฒ์ด๋ค.
@CacheEvict ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ์บ์๋ ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํ๊ฑฐ๋ ๊ฐฑ์ ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฑฐ๋ ์ญ์ ํ๋ API์์ ํด๋น ๋ฐ์ดํฐ์ ์บ์๋ฅผ ๋ฌดํจํํ์ฌ ์ต์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ํ๋๋ก ํฉ๋๋ค.
@CachePut ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ๋ฉ์๋๋ฅผ ์คํํ๊ณ ์บ์๋ฅผ ๊ฐฑ์ ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ๋ ์บ์๋ ํจ๊ป ์ ๋ฐ์ดํธํ๋ ๋ฐฉ์์ ๋๋ค.
- ์บ์ ๋ง๋ฃ ์๊ฐ: ๋ฐ์ดํฐ๋ฅผ ์ธ์ ์บ์์์ ์ ๊ฑฐํ ์ง, ์ฆ ์บ์ ๋ง๋ฃ ์๊ฐ์ ์ด๋ป๊ฒ ์ค์ ํ ์ง ๊ฒฐ์ ํด์ผ ํฉ๋๋ค. ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์ฃผ๊ธฐ๋ ์ค์๋์ ๋ฐ๋ผ ์ค์ ์ ๋ค๋ฅด๊ฒ ํด์ผ ํฉ๋๋ค.
- ์บ์ ์ผ๊ด์ฑ: ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์ ์บ์๊ฐ ์ผ๊ด์ฑ ์๊ฒ ๊ฐฑ์ ๋๋์ง ํ์ธํด์ผ ํฉ๋๋ค. ์ด๋ฅผ ์ํด @CacheEvict์ @CachePut์ ์ ์ ํ ์ฌ์ฉํ์ฌ ์บ์๋ฅผ ๋ฌดํจํํ๊ณ ๊ฐฑ์ ํ ์ ์์ต๋๋ค.