[AOP] AOP Aspect ๋ฅผ ์ด์šฉํ•œ ๋กœ๊ทธ ์ฒ˜๋ฆฌ ํ•˜๊ธฐ

    ๋ฐ˜์‘ํ˜•

    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);
        }
    
    }

     

     

    728x90
    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€