3-18 AOP의 개념과 용어

서현우·2022년 5월 19일
0

스프링의정석

목록 보기
45/85

1. 공통 코드의 분리

여러 메서드에 공통 코드를 추가해야 한다면?

class MyClass {
	//핵심기능과 부가기능이 같이 들어 있음.
	//관심사(핵심, 부가)를 나눠야 함.
	void aaa() {
		System.out.println("[befor]{");
		System.out.println("aaa() is called.");
		System.out.println("}[after]");
	}
	void aaa2() {
		System.out.println("[befor]{");
		System.out.println("aaa2() is called.");
		System.out.println("}[after]");
	}
	void bbb() {
		System.out.println("[befor]{");
		System.out.println("bbb() is called.");
		System.out.println("}[after]");
	}
}

//부가기능 분리
class MyAdvice {
	void invoke(Method m, Object obj, Object... args) throws Exception {
		System.out.println("[befor]{");
		m.invoke(obj, args); //메서드 호출
		System.out.println("}[after]");
	}
}

//주기능 분리
//중복코드 제거
class MyClass2 {
	void aaa() {
		System.out.println("aaa() is called.");	
	}
	void aaa2() {
		System.out.println("aaa2() is called.");
	}
	void bbb() {
		System.out.println("bbb() is called.");
	}
}

2. 코드를 자동으로 추가한다면, 어디에?

맨 앞, 맨 끝.
중간에는 추가 할 수 없다.
Before Advice
After Advice
Around Advice(Before + After)

3. AOP란?

관점 지향 프로그래밍.
부가 기능(advice)을 동적으로 추가해주는 기술.
(동적 추가 : 코드가 실행되는 과정에서 자동으로 추가)
메서드의 시작 또는 끝에 자동으로 코드(advice)를 추가.

5. AOP 관련 용어

target : advice가 추가딜 객체.
advice : target에 동적으로 추가될 부가 기능(코드)
join point : advice가 추가(join)될 대상(메서드)
pointcut : join point들을 정의한 패턴.(execution( com.fastcampus..*(...))
proxy : target에 advice가 동적으로 추가되어 생성된 객체.
wweaving : target에 advice를 추가해ㅓㅅ proxy를 생성하는 것.

(OOP, AOP는 모두 변경에 유리한 코드를 만들기 위해 분리 하는 것)

6. Advice의 종류

Advice의 설정은 XML과 애너테이션, 두 가지 방법으로 가능

around advice : @Around, 메서드의 시작과 끝 부분에 추가
before advice : @Before, 메서드의 시작 부분에 추가
after advice : @After, 메서드의 끝 부분에 추가
after returning : @AfterReturning, 예외 발생X시 실행되는 부가 기능
after throwing : @AfterThrowing, 예외 발생시 실행되는 부가 기능

6. pointcut expresstion

advice가 추가될 메서드를 지정하기 위한 패턴
execution(반환타입 패키지명.클래스명.메서드명(매개변수 목록))

//@Order(1), @Order(2) ...
public class LoggingAdvice
	@Around("execution(* com.fastcampus.ch3.aop.*.*(..))")
	//ProceedingJointPoint pjp //pjp는 메서드의 모든 정보
	public Object methodCallLog(ProceedingJoinPoint pjp) throws Throwable {
		long start = System.currentTimeMillis();
		System.out.println("<<[start] "
				+ pjp.getSignature().getName() + Arrays.deepToString(pjp.getArgs()));
				
		Object result = pjp.proceed(); //메서드 호출
		
		System.out.println("result = " + result);
		System.out.println("[end]>> "+ (System.currentTimeMillis() - start+"ms");
		return result; //메서드 호출결과를 반환
	}
}

AopMain.java

package com.fastcampus.ch3.aop;

import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AopMain {
    public static void main(String[] args) throws Exception {
        MyAdvice myAdvice = new MyAdvice();

        Class myClass = Class.forName("com.fastcampus.ch3.aop.MyClass");
        Object obj = myClass.newInstance();

        for(Method m : myClass.getDeclaredMethods()){
            myAdvice.invoke(m, obj, null);
        }
    }
}

class MyAdvice {
    Pattern p = Pattern.compile("a.*");

    boolean matches(Method m) {
        Matcher matcher = p.matcher(m.getName());
        return matcher.matches();
    }

    void invoke(Method m, Object obj, Object... args) throws Exception {
        if (m.getAnnotation(Transactional.class) != null)
            System.out.println("[before]{");

        m.invoke(obj, args); ///aaa(), aaa2(), bbb() 호출가능
        if(m.getAnnotation(Transactional.class) != null)
            System.out.println("}[after]");
    }
}

class MyClass {
    @Transactional
    void aaa(){
        System.out.println("aaa() is called");
    }
    void aaa2(){
        System.out.println("aaa2() is called");
    }
    void bbb(){
        System.out.println("bbb() is called");
    }
}

AopMain2.java

package com.fastcampus.ch3.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class AopMain2 {
    public static void main(String[] args) {
        ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context_aop.xml");
        MyMath mm = (MyMath) ac.getBean("myMath");
        mm.add(3, 5);
        mm.add(1, 2, 3);
        System.out.println("mm.multiply(3, 5) = " + mm.multiply(3, 5));
    }
}

LoggingAdvice.java

package com.fastcampus.ch3.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect
public class LoggingAdvice {
    @Around("execution(* com.fastcampus.ch3.aop.MyMath.add*(..))") //pointcut - 부가기능이 적용될 메서드의 패턴
    public Object methodCallLog(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("<<[start] "+pjp.getSignature().getName()+ Arrays.toString(pjp.getArgs()));


        Object result = pjp.proceed(); //target의 메서드를 호출

        System.out.println("result = " + result);
        System.out.println("[end]>> "+(System.currentTimeMillis() - start)+"ms");
        return result;

    }
}
profile
안녕하세요!!

0개의 댓글