์ถ์ฒ : ๋ด์ผ๋ฐฐ์์บ ํ
Aspect Oriented Programming : ๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ
- AOP ๊ฐ๋ ์ดํด
- '๋๋ง์ ์
๋ ์ต' ์ ์คํ๋ง AOP ์ ์ฉ
- Top5 ํ์ ์ฐพ๊ธฐ
- ์ค๋ณต ํด๋๋ช ์ ์ฅ ์ ์๋ฌ ์ฒ๋ฆฌ
- ์คํ๋ง ์์ธ ์ฒ๋ฆฌ
์๋ฒ๋ฅผ ์ฌ์ฉํ ์๊ฐ ~ ๋ชจ๋ API์ ์์ฒญ, ์๋ตํ ์๊ฐ์ ํฉ์ ๊ธฐ์ค์ผ๋ก ์์ 5์ธ ์ ๋ฐ
์คํฌ๋์น ํ์ผ์ ์ด์ฉํ ์๋ฒ ์ฌ์ฉ์๊ฐ ์ธก์
+ ์คํฌ๋์น ํ์ผ์ ๋ณ๋๋ก ์ ์ฅ๋๋ ์์ํ์ผ, ํ๋ก์ ํธ์ ๊ด๋ จ์๋ ์ฝ๋๋ฅผ ๋ค๋ฃฐ ๋ ์ ์ฉํ๋ค
class Scratch {
public static void main(String[] args) {
// ์ธก์ ์์ ์๊ฐ
long startTime = System.currentTimeMillis();
// ํจ์ ์ํ
long output = sumFromOneTo(1_000_000_000);
// ์ธก์ ์ข
๋ฃ ์๊ฐ
long endTime = System.currentTimeMillis();
long runTime = endTime - startTime;
System.out.println("์์์๊ฐ: " + runTime);
}
private static long sumFromOneTo(long input) {
long output = 0;
for (int i = 1; i < input; ++i) {
output = output + i;
}
return output;
}
}
output์ ๊ฐ์ ์ด๊ธฐ๊ฐ 1์ด๋ก ์ค์ ํ ํ, ์ฌ์ฉ์๊ฐ๋งํผ ๊ฐ์ ์ฆ๊ฐ์ํค๋ ๋ฐ๋ณต๋ฌธ์ ํตํด ์๊ฐ์ ํฉ์ ๊ตฌํ๋ค
TOP 5 ํ์ ์ฐพ๊ธฐ ์ค๊ณ ๋ฐ ๊ตฌํ
์ปฌ๋ผ๋ช | ํ์ | ์ค๋ณตํ์ฉ | ์ค๋ช |
id | Long | X | ํ ์ด๋ธ ID(PK) |
userId | Long | X | ํ์ ID(FK) |
totalTime | Long | O | API ์ด ์ฌ์ฉ์๊ฐ |
ApiUseTime ์์ฑ
ApiUseTimeRepository ์์ฑ
ProductController ์ฌ์ฉ์๊ฐ ๊ธฐ๋ก ์ถ๊ฐ
(๊ด๋ฆฌ์) ํ์๋ณ API ์ด ์ฌ์ฉ์๊ฐ ์กฐํ API ์ค๊ณ ๋ฐ ๊ตฌํ
๊ธฐ๋ฅ | ๋ฉ์๋ | URL | ์ค๋ช |
API ์ด ์ฌ์ฉ์๊ฐ ์กฐํ | GET | /api/use/time | ํ์๋ณ API ์ด ์ฌ์ฉ์๊ฐ ์กฐํ (๊ด๋ฆฌ์์ฉ) |
ApiUseTimeController ์์ฑ
AOP๋?
๊ฐ API ๋ณ ์ํํด์ผ ํ๋ ์ฃผ์ ๋น์ฆ๋์ค ๋ก์ง์ ์ ์ธํ ๋ถ๊ฐ๊ธฐ๋ฅ์ ๋ชจ๋ํํ์ฌ ๋ถ๊ฐ๊ธฐ๋ฅ ์ค์ฌ์ผ๋ก ์ค๊ณ ๊ตฌํํ๋ ๊ฒ
~ ์คํ๋ง์ด ์ ๊ณตํ๋ AOP
AOP๋ฅผ ์ฌ์ฉํด ๋ชจ๋ ์ปจํธ๋กค๋ฌ์ ๋ถ๊ฐ๊ธฐ๋ฅ ์ถ๊ฐ
package com.sparta.myselectshop.aop;
import com.sparta.myselectshop.entity.ApiUseTime;
import com.sparta.myselectshop.entity.User;
import com.sparta.myselectshop.repository.ApiUseTimeRepository;
import com.sparta.myselectshop.security.UserDetailsImpl;
import lombok.RequiredArgsConstructor;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class UseTimeAop {
private final ApiUseTimeRepository apiUseTimeRepository;
@Around("execution(public * com.sparta.myselectshop.controller..*(..))")
public synchronized Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
// ์ธก์ ์์ ์๊ฐ
long startTime = System.currentTimeMillis();
try {
// ํต์ฌ๊ธฐ๋ฅ ์ํ
Object output = joinPoint.proceed();
return output;
} finally {
// ์ธก์ ์ข
๋ฃ ์๊ฐ
long endTime = System.currentTimeMillis();
// ์ํ์๊ฐ = ์ข
๋ฃ ์๊ฐ - ์์ ์๊ฐ
long runTime = endTime - startTime;
// ๋ก๊ทธ์ธ ํ์์ด ์๋ ๊ฒฝ์ฐ, ์ํ์๊ฐ ๊ธฐ๋กํ์ง ์์
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getPrincipal().getClass() == UserDetailsImpl.class) {
// ๋ก๊ทธ์ธ ํ์ ์ ๋ณด
UserDetailsImpl userDetails = (UserDetailsImpl) auth.getPrincipal();
User loginUser = userDetails.getUser();
// API ์ฌ์ฉ์๊ฐ ๋ฐ DB ์ ๊ธฐ๋ก
ApiUseTime apiUseTime = apiUseTimeRepository.findByUser(loginUser)
.orElse(null);
if (apiUseTime == null) {
// ๋ก๊ทธ์ธ ํ์์ ๊ธฐ๋ก์ด ์์ผ๋ฉด
apiUseTime = new ApiUseTime(loginUser, runTime);
} else {
// ๋ก๊ทธ์ธ ํ์์ ๊ธฐ๋ก์ด ์ด๋ฏธ ์์ผ๋ฉด
apiUseTime.addUseTime(runTime);
}
log.info("[API Use Time] Username: " + loginUser.getUsername() + ", Total Time: " + apiUseTime.getTotalTime() + " ms");
apiUseTimeRepository.save(apiUseTime);
}
}
}
}
AOP ์ ์ฉ ์
AOP ์ ์ฉ ํ
์คํ๋ง AOP ์ด๋ ธํ ์ด์ ์ ์ข ๋ฅ
1. @Aspect
์คํ๋ง ๋น ํด๋์ค์ ์ ์ฉ๊ฐ๋ฅ
2. ์ด๋๋ฐ์ด์ค์ ์ข ๋ฅ ~ AOP ์ฝ๋๊ฐ ์คํ๋๋ ์์ ์ ์ง์ ํด์ค๋ค
- @Around : 'ํต์ฌ๊ธฐ๋ฅ' ์ํ ์ ๊ณผ ํ(@Before + @After)
- @Before : 'ํต์ฌ๊ธฐ๋ฅ' ์ํ ์ (ex : Client์ ์ ๋ ฅ๊ฐ Vaildation ์ํ)
- @After : 'ํต์ฌ๊ธฐ๋ฅ' ์ํ ์ฑ๊ณต/์คํจ ์ฌ๋ถ์ ๊ด๊ณ์์ด ์ธ์ ๋ ๋์ (try, catch์ finally()์ ๊ฐ์ ๋์ ๋ฐฉ์)
- @AfterReturning : 'ํต์ฌ๊ธฐ๋ฅ' ํธ์ถ ์ฑ๊ณต์ ๋์ํ์ฌ ํจ์์ Return๊ฐ ์ฌ์ฉ๊ฐ๋ฅ
- @AfterThrowing : 'ํต์ฌ๊ธฐ๋ฅ' ํธ์ถ ์คํจ์, ์์ธ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ์๋ง ๋์ (ex : ์์ธ๋ฐ์์ ๊ฐ๋ฐ์์๊ฒ ํต์ง๊ธฐ๋ฅ)
3. ํฌ์ธํธ์ปท ~ AOP ์ฝ๋๊ฐ ์คํ๋๋ ์ฅ์๋ฅผ ์ ํด์ค๋ค
์์ -> @์ด๋๋ฐ์ด์ค(ํฌ์ธํธ์ปท)์ ํํ
execution(
modifiers-pattern?
return-type-pattern declaring-type-pattern?
method-name-pattern(param-pattern) throws-pattern?)โ
@Around("execution(public * com.sparta.springcore.controller..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { ... }
modifiers-pattern : pubilc, private, *
return-type-pattern : void, String, List<String>, *
declaring-type-pattern : ํด๋์ค๋ช (ํจํค์ง๋ช ํ์)
~ com.sparta.springcore.controller.* : controller ํจํค์ง์ ๋ชจ๋ ํด๋์ค์ ์ ์ฉ
~ com.sparta.springcore.controller.. : controller ํจํค์ง ๋ฐ ํ์ ํจํค์ง์ ๋ชจ๋ ํด๋์ค๊น์ง ์ ์ฉ
method-name-pattern(param-pattern)
ํจ์๋ช
addFolders : addFolders() ํจ์์๋ง ์ ์ฉ
add* : add๋ก ์์ํ๋ ๋ชจ๋ ํจ์์ ์ ์ฉ
ํ๋ผ๋ฏธํฐ ํจํด
(com.sparta.springcore.dto.FolderRequestDto) - FolderRequestDto ์ธ์์๋ง ์ ์ฉ
() - ์ธ์ ์์
(*) - ํ์ ์๊ด์์ด ์ธ์ 1๊ฐ
(..) - ํ์ ์๊ด์์ด ์ธ์ 1~N๊ฐ
'Spring๐' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring Transaction (0) | 2022.12.29 |
---|---|
Spring Exception (0) | 2022.12.29 |
ํ ์คํธ ์ฝ๋ (0) | 2022.12.27 |
OAuth2 (0) | 2022.12.27 |
์คํ๋ง ์๋ จ : Project MySelectShop (3) (0) | 2022.12.15 |