13_spring_(AOP)

13_spring_(AOP)

관점 지향 프로그래밍(Aspect Oriented Programming)

공통되는 부분을 따로 빼내어 필요한 시점에 해당코드를 추가해주는 기술

Advice : 공통되는 부분을 따로 빼내어 작성하는 메소드

JoinPoint : Advice를 적용될 수 있는 모든 관점(시점)

PointCut : JoinPoint 중 실제 Advice를 적용할 부분

Weaving : 그 시점에 공통 코드를 끼워 넣는 작업(런타임 시 위빙 (Spring)

Aspect : Advice + PointCut (동적) , 여러 객체에 공통으로 적용되는 기능을 분리하여 작성한 클래스

Proxy : 대상 객체를 직접 접근하지 못하게 '대리인'으로써 요청을 대신 받는 기술

@Before("pointcut") / After("pointcut") / Around("pointcut")

* 모든 어드바이스는 JoinPoint 타입의 파라미터를 첫번재 매개변수로 선언해야한다.

단, Around 어드바이스는 joinPoint의 하위 클래스인 ProceedingJoinPoint 타입의 파라미러를 필수로 선언해야한다

LogAdvice

@Component // Spring 컨테이너가 @Aspect가 적용된 객체를 // 제어(IOC)해야 하므로 Bean 으로 등록되어 있어야 함 @Aspect // 해당 클래스가 AOP에 사용될 것이라는 걸 명시 // Aspect = advice + pointcut public class LogAdvice { // Pointcut 지정 : advice가 적용될 부분 지정 // execution : 특정 객체(메소드)가 실행(호출) 되는 시점 // execution([접근제한자] [리턴타입] [클래스명] [메소드명] [파라미터]) // * : 모두 // .. : 이하 모두 // *Impl : 클래시명 마지막이 Impl인 클래스 // Aspect는 필드선언이 안됨 메소드로 작성 // 별도의 Pointcut을 지정하여 필요할때 호출하여 사용 // @Pointcut("execute(* com.kh.spring..*Impl.*(..))") // public void implPointcut() {} // before Advice //@Before("execute(* com.kh.spring.*Impl.*(..))") //@Before("implPointcut()") @Before("CommonPointcut.implPointcut()") public void startLog(){ System.out.println("[log] : 비즈니스 로직 시작"); } // @After : 예외 발생 여부와 관계 없이 무조건 실행됨 // after advice // @After("execution("* com.kh.spring.*Impl.*(..))") @After("CommonPointcut.implPointcut()") public void endLog() { System.out.println("[log] : 비즈니스 로직 종료"); } }

공용으로 사용될 Pointcut을 모아둔 클래스

// 공용으로 사용될 Pointcut을 모아둔 클래스 public class CommonPointcut { @Pointcut("execution(* com.kh.spring.*Impl.*(..))") public void implPointcut(){} }

BeforeAdvice

@Component @Aspect public class BeforeAdvice { @Before("CommonPointcut.implPointcut()") public void beforeLog(JoinPoint jp) { // jp.getTarget() : 대상 객체 반환 // jp.getSigniture() : 대상 객체 메소드 정보 반환 String className = jp.getTarget().getClass().getSimpleName(); String methodName = jp.getSignature().getName(); System.out.println("-------------------------------------------"); System.out.println("[전처리] : " + className + " - " + methodName + "() - start"); } }

AfterAdvice

@Component // bean 등록 @Aspect // advice + pointcut public class AfterAdvice { @After("CommonPointcut.implPointcut()") public void afterLog(JoinPoint jp) { // jp.getTarget() : 대상 객체 반환 // jp.getSigniture() : 대상 메소드 반환 String className = jp.getTarget().getClass().getSimpleName(); String methodName = jp.getSignature().getName(); System.out.println("[후처리] : " + className + " - " + methodName +"() - end"); System.out.println("------------------------------------------------------------"); }

AroundAdvice

@Component // bean 등록 @Aspect // advice+pointcut public class AroundAdvice { // @Around = @Before + @After // ProceedingJoinPoint.proceed() : 전, 후 처리 기준점 역할 // ProceedingJoinPoint는 JoinPoint를 상속받은 클래스 @Around("CommonPointcut.implePointcut()") public Object aroundLogs(ProceedingJoinPoint jp) throws Throwable { // 메소드 수행시간 체크 String methodName = jp.getSignature().getName(); // StopWatch : 스프링에서 제공하는 스톱워치 클래스 StopWatch sw = new StopWatch(); sw.start(); // 시간 측정 시작 // 여기까지가 Before Object obj = jp.proceed(); // 여기이후가 After sw.stop(); // 시간측정종료 System.out.println(methodName + "() 수행시간 : " + sw.getTotalTimeMillis() + "(ms)"); return obj; } }

AfterReturningAdvice (리턴된 데이터 중간에 가져오기)

@Component // bean 등록 @Aspect // advice + pointcut @public class AfterReturningAdvice { // login*(*) -> 메소드명이 login으로 시작하는 메소드이면서 // 매개변수(파라미터)가 한개인 메소드 // 리턴된 데이터 강탈 @AfterReturning(pointcut = "execution("* com.kh.spring..*Impl.login*(*))", returning = "returnObj") // 위에 선언한 returnObj 가 파라미터로 들어감 public void loginLog(JoinPoint jp, Object returnObj) { // 접속자 IP 얻어오기 HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder .currentRequestAttributes()).getRequest(); String ip = request.getRemoteAddr(); String logMsg = "[IP : " + ip + "] : "; if(returnObj instanceof Member) { Member member = (Member)returnObj; if(member.getMemberId().equals("admin")) { logMsg += "관리자 로그인"; } else { logMsg += "ID : " + member.getMemberId() + "로그인"; } System.out.println(logMsg); } } }

AfterThrowingAdvice (중간에 에러잡기)

@Component @Aspect public class AfterThrowingAdvice { @AfterThrowing(pointcut = "CommonPointcut.implPointcut()", throwing = "exceptionObj") public void exceptionLog(JoinPoint jp, Exception exceptionObj) { // SyntaxErrorException // -> "SQL 구문 에러" String logMsg = "예외 발생 내용 : "; if(exceptionObj instanceof IllegalArgumentException) { logMsg += "부적합한 값 입력"; } else if(exceptionObj instanceof BadSqlGrammarException) { logMsg += "SQL 문법 오류"; } else { logMsg += "기타 예외 발생"; } System.out.println(logMsg); } }

from http://spike1574.tistory.com/113 by ccl(A) rewrite - 2020-03-17 16:54:31

댓글

이 블로그의 인기 게시물

데이터 바인딩 추상화 - propertyEditor

[샤니마스 SPRING PARTY2020] THE IDOLM @ STER SHINY COLORS SPRING...

Spring Web Form