AOP는 문제를 바라보는 관점을 기준으로 프로그래밍하는 기법입니다. 이를 통해 핵심 관심 사항과 공통 관심 사항을 분리하여 각각의 역할에 집중할 수 있습니다. 예를 들어, 로깅, 보안, 트랜잭션 관리 등 여러 메서드나 클래스에 걸쳐 반복적으로 발생하는 "공통 관심 사항"을 분리하여 코드를 간결하고 유지보수하기 쉽게 만듭니다.
핵심 관심 사항 (Core Concern)
공통 관심 사항 (Cross-Cutting Concern)
횡단 관심사의 분리 (Separation of Cross-Cutting Concern)
위빙 (Weaving)
Advice (보조 작업)
@Before: 메서드 실행 이전 실행. @After: 메서드 실행 이후 실행. @Around: 메서드 실행 전/후 실행. @AfterReturning: 정상적으로 메서드 실행 후 동작. @AfterThrowing: 메서드 실행 중 예외 발생 시 동작.JoinPoint (합류 지점)
Pointcut (지점 설정)
execution, within, bean)으로 정의됩니다.Aspect (관점)
Target (대상)
Proxy (프록시)
Maven Repository에서 spring-boot-starter-aop를 추가합니다.
application.properties에서 AOP 관련 설정:spring.aop.auto=true
spring.aop.proxy-target-class=trueproxy-target-class=true: CGLIB 프록시 사용.proxy-target-class=false: JDK Dynamic Proxy 사용.// 인터페이스
public interface Target {
String sayEcho( String name );
}
// 클래스
import org.springframework.stereotype.Service;
@Service( "target" )
public class TargetService implements Target {
// 핵심 사항
@Override
public String sayEcho(String name) {
//System.out.println( "전처리" );
System.out.println( "sayEcho(String name) 호출" );
//System.out.println( "후처리" );
return "Hi " + name;
}
}
execution 표현식을 사용하여 특정 메서드 패턴을 설정package org.example.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
@Configuration
@Aspect
public class BasicAdvice1 {
@Pointcut( "execution(public * say*(..))" )
public void myTarget() {
}
@Around( "myTarget()" )
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Object obj = null;
System.out.println( "전처리 구간" );
// 핵심 사항 실행
obj = joinPoint.proceed();
System.out.println( "후처리 구간" );
return obj;
}
}
메인 클래스
package org.example;
import org.example.model.Target;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class Di02Application implements CommandLineRunner {
@Autowired
private ApplicationContext ctx;
public static void main(String[] args) {
SpringApplication.run(Di02Application.class, args);
}
@Override
public void run(String... args) throws Exception {
Target target = ctx.getBean("target", Target.class);
System.out.println(target.sayEcho("홍길동"));
}
}
@Around 사용)특정 메서드의 실행 속도를 측정하는 AOP 구현:
@Aspect
@Configuration
public class PerformanceAdvice {
@Pointcut("execution(public * say*(..))")
public void myTarget() {}
@Around("myTarget()")
public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.nanoTime();
Object result = joinPoint.proceed(); // 핵심 로직 실행
long endTime = System.nanoTime();
System.out.println("메서드 실행 시간: " + (endTime - startTime) + "ns");
return result;
}
}
WriteAction의 실행 전처리와 ListAction의 실행 후처리를 적용.@Aspect
@Configuration
public class BasicAdvice {
@Before("bean(*write*)")
public void before(JoinPoint joinPoint) {
System.out.println("전처리: " + joinPoint.getSignature().getName());
}
@After("bean(*list*)")
public void after(JoinPoint joinPoint) {
System.out.println("후처리: " + joinPoint.getSignature().getName());
}
}
@SpringBootApplication
public class AopApplication implements CommandLineRunner {
@Autowired
private ApplicationContext ctx;
public static void main(String[] args) {
SpringApplication.run(AopApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
WriteAction writeAction = ctx.getBean("write", WriteAction.class);
writeAction.execute(); // 전처리 적용
ListAction listAction = ctx.getBean("list", ListAction.class);
listAction.execute(); // 후처리 적용
}
}
AOP는 핵심 로직에 영향을 주지 않으면서 공통된 요구 사항을 처리할 수 있어, 코드의 재사용성과 유지보수성을 크게 향상시킵니다.