AOP ๋ฐ ๊ตฌ์ฑ์์ ๊ฐ๋จ ์ค๋ช
์คํ๋ง ํต์ฌ ๊ตฌ์ฑ ์์ ์ค ํ๋์ธ AOP ๋ ๋ก์ง์ ๊ด์ฌ์ฌ(Aspect)๋ผ๋ ๋ถ๋ถ์ผ๋ก ๋๋๋ ๊ฒ์ผ๋ก ์์ํฉ๋๋ค.
OOP์์ ๋ชจ๋ํ์ ํต์ฌ ๋จ์๋ ํด๋์ค์ธ ๋ฐ๋ฉด, AOP์ ๋ชจ๋ํ ๋จ์๋ Aspect ์
๋๋ค.
์ข
์์ฑ ์ฃผ์
์ ์ ํ๋ฆฌ์ผ์ด์
๊ฐ์ฒด๋ฅผ ์๋ก ๋ถ๋ฆฌํ๋๋ฐ ๋์์ด ๋๊ณ , AOP๋ ๊ฐ์ฒด์ ํก๋จ ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌํ๋๋ฐ ๋์์ด ๋ฉ๋๋ค.
[์ฉ์ด ์ค๋ช ]
Aspect
- ํก๋จ ๊ด์ฌ์ฌ๋ฅผ ์ ๊ณตํ๋ ๋ชจ๋, ์๋ฅผ ๋ค์ด ์ง๊ธ ์์ฑํ๋ คํ๋ ๋ก๊น
์ ์ํ ๋ชจ๋์ ๋ก๊น
์ ์ํ Aspect ๋ผ๊ณ ํ๋ค.
Join Point
- AOP ํ๋ก๊ทธ๋จ์ ์ฌ์ฉํ์ฌ ์์
ํ ์ ํ๋ฆฌ์ผ์ด์
์ ์์น
Advice
- ๋ฉ์๋ ์คํ ์ ์ด๋ ํ์ ์ทจํด์ผ ํ ์ค์ ์กฐ์น
Point Cut
- Advice๊ฐ ์คํ๋๋ ํ๋ ์ด์์ Join Point ์์น, ํํ์์ด๋ ํจํด์ ์ด์ฉํด ์ง์ ๊ฐ๋ฅ.
Target Object
- ํ๋ ์ด์์ Aspect ์์ Advice ๊ฐ ์คํ๋๋ ๊ฐ์ฒด. ํญ์ ํ๋ก์ ๊ฐ์ฒด์ด๋ค.
Advice Type
before - ๋ฉ์๋ ์คํ ์
after - ๋ฉ์๋ ์คํ ํ(์๋ฌ ๊ด๊ณ์์ด)
after-returning - ๋ฉ์๋ "์ ์" ์คํ ํ
after-throwing - ๋ฉ์๋ ์คํ ์, ์๋ฌ throwingํ ๊ฒฝ์ฐ
around - ๋ฉ์๋ ์คํ ์ /ํ
From : https://www.tutorialspoint.com/springaop/springaop_implementations.htm
Spring AOP - Implementations
Spring AOP - Implementations Spring supports the @AspectJ annotation style approach and the schema-based approach to implement custom aspects. XML Schema Based Aspects are implemented using regular classes along with XML based configuration. To use the AOP
www.tutorialspoint.com
Log Aspect ์์ฑ
์ฐ๋ฆฌ๊ฐ ์์ฑํ๋ ์ฝ๋์ ๋ชฉ์ ์, ๋ก๊ทธ ์คํ ์ /ํ์ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๋ฉฐ, ์๋ฌ์ ์ ์ ์คํ์ ๊ตฌ๋ถํ์ฌ ๊ธฐ๋ก์ ๋จ๊ธฐ๋ ค ํ๋ค.
๋ํ, ํน์ ์ปจํธ๋กค๋ฌ์๋ง ์ ์ฉ ์ํค๊ฑฐ๋ ์์น ์๋ URL ๋๋ ๋ฉ์๋ ์ธ ๊ฒฝ์ฐ ์ ์ธํ๊ณ ์ ํ๋ค.
๋จ์ํ, ์คํ ์ /ํ๋ฅผ ๊ตฌ๋ถํ์ฌ ํน์ ์ปจํธ๋กค๋ฌ Path ๋ก๋ง Aspect ๋ฅผ ์ก๊ฒ ๋๋ฉด ํด๋น ์ปจํธ๋กค๋ฌ ๋ด์ ์๋ ์ ์ธ๋์ด์ผ ํ๋ ํน์ ์ ์ธํ๊ณ ์ ํ๋ ๋ฉ์๋๋ฅผ ๊ตฌ๋ถํด๋ด๊ธฐ๋ ์ฝ์ง ์๋ค.
๋ฐ๋ผ์, ์๋ฌด ์์ ์ ํ์ง ์๋ ๋น Annotation์ ๋ง๋ค์ด, ํด๋น Annotation์ Aspect์์ ์ ์ธ ์ํค๋ฉด, ์๊ธฐ ๋ชฉ์ ์ ์ด๋ฃฐ ์ ์๋ค.
์ด๋ ๋ค์๊ณผ ๊ฐ์ PointCut ํํ์์ผ๋ก ๊ตฌํ์ด ๊ฐ๋ฅํ๋ค.NoLogging.java
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface NoLogging {
}
* ์ฌ์ฉ
@NoLogging
@RestController
public void index() {
...
}
๊ทธ๋ฆฌ๊ณ PoingCut์ ๋ค์๊ณผ ๊ฐ์ ํํ์์ ์์ฑํ๋ค
@Pointcut("execution(* com.example.controller..*.*(..)) && !@annotation(com.example.aspect.NoLogging)")
private void cut() {
// ์ปจํธ๋กค๋ฌ ๊ฒฝ๋ก ๋ด๋ถ ๋ชจ๋ ๋ฉ์๋ + NoLogging ์ด๋
ธํ
์ด์
๋ถ์ด์๋ ๋ฉ์๋ ์ ์ธ
}
์์ ๊ฐ์ PointCut ์ ๋ง๋ค๊ณ , Advice์ ์ ์ฉํด์ฃผ๋ฉด ๋๋ค. ์๋๋ ์์ฑํ ์ฝ๋์ด๋ค.
LogAspect.java
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
// ๋ก๊ทธ ์ ์ฅ์ฉ ์๋น์ค
@Autowired
LogSvc svc;
/**
* Log Aspect๋ฅผ ์ ์ฉํ ํจํค์ง/ํ์
/๊ฒฝ๋ก
*
* ex) controller ๊ฒฝ๋ก / service ๊ฒฝ๋ก / ๋ฉ์๋ ๋ฑ
* ํน์ ํด๋(ํจํค์ง) : com.example.controller.menuMngt..*.*(..)
* ํน์ ๋ฉ์๋(ํ๋ผ๋ฏธํฐํฌํจ) : com.example.service.findId(HashMap<String, Object>)
*
* [๊ตฌ์กฐ]
* 1. * : ๋ฆฌํด ํ์
์ง์ (*:anything | public string | ...)
* 2. com.acaas.admin.controller..*.* : ํจํค์ง ๊ฒฝ๋ก ๋ฐ ๋ฉ์๋ ๋ช
๋ฑ
* 3. (..) : ํ๋ผ๋ฏธํฐ ํ์
*
* .. ๋ ๋ง์ ์ ๋ณด : https://www.baeldung.com/spring-aop-pointcut-tutorial
*
* '!@annotation(com.acaas.admin.aspect.NoLogging)'
* NoLogging ์ด๋
ธํ
์ด์
์ด ๋ถ์ ๋ฉ์๋๋ ์ ์ธํ๋ค.
*/
@Pointcut("execution(* com.acaas.admin.controller..*.*(..)) && !@annotation(com.acaas.admin.aspect.NoLogging)")
private void cut() {
}
/**
* ๋ฉ์๋ ์ ๊ตฌ์ญ
*
* @param jp
*/
@Around("cut()")
public void Around(JoinPoint jp) {
logInsert(jp);
}
/**
* ๋ฉ์๋ ์คํ ์
*
* @param jp
*/
@Before("cut()")
public void Before(JoinPoint jp) {
String logType = "Before";
logInsert(jp, logType, "-", "");
}
/**
* ๋ฉ์๋ ์คํ ํ <๊ธฐ๋ณธ>
* !! AfterReturning ๊ณผ Throwing ์ ์ฌ์ฉํ๋ค๋ฉด, ๊ธฐ๋ณธ After๋ ์ฌ์ฉํ์ง ๋ง์์ผ ์ค๋ณต ์คํ ๋ฐฉ์ง ๊ฐ๋ฅํจ. !!
*
* @param jp
*/
/*
* @After("cut()")
* public void After(JoinPoint jp) {
* String logType = "After";
* logInsert(jp, logType);
* }
*/
/**
* ๋ฉ์๋ ์ ์ ์ข
๋ฃ ํ
*
* @param jp
*/
@AfterReturning("cut()")
public void AfterReturning(JoinPoint jp) {
String logType = "AfterReturning";
logInsert(jp, logType, "200", "");
}
/**
* ๋ฉ์๋ ์๋ฌ ( Exception ) ๋ฆฌํด ๊ฒฝ์ฐ
*
* @param jp
*/
@AfterThrowing(value = "cut()", throwing = "e")
public void AfterThrowing(JoinPoint jp, Exception e) {
String logType = "AfterThrowing";
logInsert(jp, logType, "500", e.getMessage());
}
/**
* ์คํ๋ ๋ฉ์๋ ๋ช
๊ฐ์ ธ์ค๊ธฐ
*
* @param joinPoint
* @return
*/
private Method getMethod(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
return signature.getMethod();
}
/**
* ๋ก๊ทธ ์์
๊ตฌ๊ฐ
* ์ปค์คํฐ๋ง์ด์ง ๊ตฌ๊ฐ
*
* @param jp
* @param logType
* @param status
* @param errorLog
* @return
*/
private int logInsert(JoinPoint jp, String logType, String status, String errorLog) {
// ๋ฉ์๋ ๋ช
: ํ์ํ ๊ฒฝ์ฐ ์ฌ์ฉ
Method method = getMethod(jp);
// ๋ฉ์๋ ์คํ ์ ์
๋ ฅ๋ ํ๋ผ๋ฏธํฐ ๊ฐ์ ธ์ค๊ธฐ
Object[] args = jp.getArgs();
// ํ๋ผ๋ฏธํฐ ๋ด์ฉ ๊ฐ์ ธ์ค๊ธฐ
HashMap<String, Object> paramMap = new HashMap<String, Object>();
for (Object arg : args) {
String type = arg.getClass().getSimpleName();
// ํน์ ํ์
๋ง ๊ฐ์ ธ์ค๊ธฐ
if (type.equals("HashMap<String, Object>")) {
paramMap.putAll((HashMap<String, Object>) arg);
}
}
// url check
String chkUrl = paramMap.getStr("mappingUrl");
boolean pass = this.chkUrl(chkUrl, paramMap);
// url pass ?
if (pass) {
// ๋ก๊ทธ ํ
์ด๋ธ์ ์ ์ฅ
HashMap<String, Object> logMap = new HashMap<String, Object>();
String userId = "";
String userNm = "";
if (JavaUtil.NVL(paramMap.get("session"), "").equals("")) {
userId = "No Session :: userId";
userNm = "No Session :: userNm";
} else {
userId = paramMap.get("session").getStr("id");
userNm = paramMap.get("session").getStr("nm");
}
String url = paramMap.getStr("mappingUrl");
String description = this.getDescription(url, paramMap);
String urlParameter = paramMap.toString();
logMap.put("logType", logType);
logMap.put("userId", userId);
logMap.put("userNm", userNm);
logMap.put("url", url);
logMap.put("description", description);
logMap.put("urlParameter", urlParameter);
logMap.put("status", status);
logMap.put("errorLog", errorLog);
logger.info("[Aspect] " + logType + " logMap : " + logMap);
return svc.logInsert(logMap);
} else {
// none
return -500;
}
}
/**
* URL check <DB>
*
* @param url
* @param paramMap
* @return
*/
public boolean chkUrl(String url, HashMap<String, Object> paramMap) {
String splitUrl = url.split("/admin")[1];
logger.info("[LOG] chkUrl : " + splitUrl);
// 1. ๋ธ๋๋ฆฌ์คํธ ๋ฐฉ์์ผ๋ก ์ ์ธ URL ์ฒดํฌ
if (svc.chkTask(splitUrl, "black") > 0) {
return false;
} else {
// 2. ํ์ดํธ๋ฆฌ์คํธ ๋ฐฉ์์ผ๋ก DB์ ๋ฑ๋ก๋ task์ ์ผ์นํ๋์ง ์ฒดํฌ
if (svc.chkTask(splitUrl, "white") > 0) {
return true;
} else {
return false;
}
}
}
/**
* ํด๋น ์์
๋งคํ๋ ์์
๋ด์ฉ ๊ฐ์ ธ์ค๊ธฐ <DB>
*
* @param url
* @param paramMap
* @return
*/
public String getDescription(String url, HashMap<String, Object> paramMap) {
String splitUrl = url;
return svc.getDescription(splitUrl);
}
}
'๐ฎSpring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SpringBoot] Rest Api Sample ๋ง๋ค๊ธฐ #1 (0) | 2022.07.05 |
---|---|
[SpringBoot] CORS ์ฒ๋ฆฌํ๊ธฐ (0) | 2022.06.28 |
[Spring Boot] ํ์ผ ์ ๋ก๋ ๋ง๋ค๊ธฐ -4- (0) | 2022.03.30 |
[Spring Boot] ํ์ผ ์ ๋ก๋ ๋ง๋ค๊ธฐ -3- (0) | 2022.03.27 |
[Spring Boot] ํ์ผ ์ ๋ก๋ ๋ง๋ค๊ธฐ -2- (0) | 2022.03.25 |
๋๊ธ