AOP, Aspect Oriented Programming

ํŠน์ •ํ•œ ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ „์ด๋‚˜ ํ›„์˜ ๊ณตํ†ต์ ์ธ ์ฒ˜๋ฆฌ์— ์‚ฌ์šฉ๋œ๋‹ค. (๋กœ๊น…, ํŠธ๋žœ์žญ์…˜, ์ธ์ฆ)ใ…

AOP์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๋“ค

Aspect

์—ฌ๋Ÿฌ ํด๋ž˜์Šค๋‚˜ ๊ธฐ๋Šฅ์— ๊ฑธ์ณ์„œ ์žˆ๋Š” ๊ด€์‹ฌ์‚ฌ, ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ๋“ค์„ ๋ชจ๋“ˆํ™”ํ•˜๋Š” ๊ฒƒ. ๊ฐ€์žฅ ๋งŽ์ด ํ™œ์šฉ๋˜๋Š” ๋ถ€๋ถ„์€ @Transactional ๊ธฐ๋Šฅ

Advice

AOP์—์„œ ์‹ค์ œ๋กœ ์ ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ (๋กœ๊น…, ํŠธ๋žœ์žญ์…˜, ์ธ์ฆ ๋“ฑ)

Join point

Aspect ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ์—ฐ๊ฒฐ ํฌ์ธํŠธ

Pointcut

Join point ์ค‘์—์„œ Aspect ๋ฅผ ์ ์šฉํ•  ๋Œ€์ƒ์„ ๋ฝ‘์„ ์กฐ๊ฑด์‹

Target Object

Advice๊ฐ€ ์ ์šฉ๋  ๋Œ€์ƒ ์˜ค๋ธŒ์ ํŠธ

AOP Proxy

๋Œ€์ƒ ์˜ค๋ธŒ์ ํŠธ์— Aspect ๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒฝ์šฐ Advice ๋ฅผ ๋ง๋ถ™์ด๊ธฐ ์œ„ํ•ด ํ•˜๋Š” ์ž‘์—… ์ฃผ๋กœ CGLIB (Code Generation Library, ์‹คํ–‰ ์ค‘์— ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ) ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋ก์‹ฑ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.

Weaving

Advice ๋ฅผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฝ”๋“œ์— ์‚ฝ์ž…ํ•˜๋Š” ๊ฒƒ.

AspectJ

AOP๋ฅผ ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๊ผญ ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต๋˜๋Š” Spring AOP ๋กœ๋Š” ๋‹ค์–‘ํ•œ ๊ธฐ๋ฒ•์˜ AOP๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ. (Pointcut ๋“ฑ)

Aspect์˜ ์ƒ์„ฑ

package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
@Component  // Component๋ฅผ ๋ถ™์ธ ๊ฒƒ์€ ํ•ด๋‹น Aspect๋ฅผ ์Šคํ”„๋ง์˜ Bean์œผ๋กœ ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ
public class UsefulAspect {

}

Pointcut ์„ ์–ธ

package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
@Component  // Component๋ฅผ ๋ถ™์ธ ๊ฒƒ์€ ํ•ด๋‹น Aspect๋ฅผ ์Šคํ”„๋ง์˜ Bean์œผ๋กœ ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ
public class UsefulAspect {

	@Pointcut("execution(* transfer(..))")
	private void anyOldTransfer() {}
}
  • ํ•ด๋‹น Aspect์˜ Advice ๊ฐ€ ์ ์šฉ๋  Join point ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ํŒจํ„ด ๋˜๋Š” ์กฐ๊ฑด ์ƒ์„ฑ

  • ํฌ์ธํŠธ ์ปท ํ‘œํ˜„์‹์ด๋ผ๊ณ  ๋ถ€๋ฆ„

Pointcut ๊ฒฐํ•ฉ

package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
@Component  // Component๋ฅผ ๋ถ™์ธ ๊ฒƒ์€ ํ•ด๋‹น Aspect๋ฅผ ์Šคํ”„๋ง์˜ Bean์œผ๋กœ ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ
public class UsefulAspect {

	@Pointcut("execution(public * *(..))")
	private void anyPublicOperation() {} //public ๋ฉ”์„œ๋“œ ๋Œ€์ƒ ํฌ์ธํŠธ ์ปท

	@Pointcut("within(com.xyz.myapp.trading..*)")
	private void inTrading() {} // ํŠน์ • ํŒจํ‚ค์ง€ ๋Œ€์ƒ ํฌ์ธํŠธ ์ปท
	
	@Pointcut("anyPublicOperation() && inTrading()")
	private void tradingOperation() {} // ์œ„์˜ ๋‘ ์กฐ๊ฑด์„ and(&&) ์กฐ๊ฑด์œผ๋กœ ๊ฒฐํ•ฉํ•œ ํฌ์ธํŠธ ์ปท
}

Advice ์ •์˜

ํฌ์ธํŠธ ์ปท๋“ค์„ ํ™œ์šฉํ•˜์—ฌ ํฌ์ธํŠธ์ปท์˜ ์ „/ํ›„/์ฃผ๋ณ€์—์„œ ์‹คํ–‰๋  ์•ก์…˜์„ ์ •์˜ํ•จ

Before Advice

dataAccessOperation() ์ด๋ผ๋Š” ๋ฏธ๋ฆฌ ์ •์˜๋œ ํฌ์ธํŠธ ์ปท์˜ ๋ฐ”๋กœ ์ „์— doAccessCheck() ๊ฐ€ ์‹คํ–‰

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class BeforeExample {

    @Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
    public void doAccessCheck() {
        // ...
    }
}

After Returning Advice

dataAccessOperation() ๋ผ๋Š” ๋ฏธ๋ฆฌ ์ •์˜๋œ ํฌ์ธํŠธ์ปท์—์„œ return ์ด ๋ฐœ์ƒ๋œ ํ›„ ์‹คํ–‰

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;

@Aspect
public class AfterReturningExample {

    @AfterReturning("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
    public void doAccessCheck() {
        // ...
    }
}

Around Advice

businessService() ๋ผ๋Š” ํฌ์ธํŠธ์ปท์˜ ์ „/ํ›„์— ํ•„์š”ํ•œ ๋™์ž‘์„ ์ถ”๊ฐ€ํ•จ

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;

@Aspect
public class AroundExample {

    @Around("com.xyz.myapp.CommonPointcuts.businessService()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }
}

Last updated

Was this helpful?