728x90
300x250

[Spring-Framework] 31. AOP(Aspect-Oriented-Programming) 관점지향 프로그래밍 (Java셋팅) (2)


1부에서는 통상적인 개발 방법으로 간단한 Calculator 클래스에 정의된 sum 함수(또는 매서드)를 출력하는 방법을 살펴보았다.

참고로 앞에 코드는 편집이 불가능한 코드라고 가정하고 접근해야 한다.


1. [Spring-Framework] 31. AOP(Aspect-Oriented-Programming) 관점지향 프로그래밍 (Java셋팅) (1)

https://yyman.tistory.com/1447



8. aop 패키지를 추가로 작성하여 copy & paste하기


aop 패키지를 별도로 둘 것이다.

코드를 따로 작성해야 하는가? 시점 부분만 작성하고 크게 많이 작성하진 않는다.



그림 15. Copy & Paste 하기


태스트 코드를 복사할 것이다.


(1단계) com.local.example.service에 만들어놓았던 Calculator.java를 파일 복사한다. (Ctrl + C)

(2단계) com.local.example.aop 폴더(또는 패키지)를 만든다.

(3단계) com.local.example.aop 폴데 Calculator.java를 붙여넣는다. (Ctrl + V)

(4단계) 소스 코드가 빨간 불이 들어오는 패키지 부분을 com.local.example.aop로 변경해준다.



9. 작업 방법론 - 정리해보기


직관적으로 코드 작성 전략을 소개해주려고 한다.

이런 형태로 작업을 할 것이다.



그림 16. 작업 방법


빌드하는 방법은 웹 서버에 올려서 확인하면 된다.




9. AOP 필수(코어), 핵심사항 - RootConfig.java (환경설정 파일 만들기)


패키지 경로: com.local.example.aop


반드시 만들어야 할 파일이다.

이 셋팅 파일이 없으면 동작 자체를 안 한다.



그림 17. RootConfig.java


이 코드는 AspectJ Proxy의 핵심 환경설정 파일이다.

이걸 정의하지 않으면, 동작이 안 된다.


package com.local.example.aop;


import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;


@Configuration

@ComponentScan(basePackages = {"com.local.example.aop"})

//@ComponentScan(basePackages = {"com.local.example.beans", "com.local.example.advisor"})

@EnableAspectJAutoProxy

public class RootConfig {


}


파일명: RootConfig.java


[첨부(Attachments)]

RootConfig.zip




10. AOP 적용, 핵심사항 - Calculator.java (살짝 수정하기)


패키지 경로: com.local.example.aop


작업 파일 원본의 권한을 가진 사람에게 하나 요청해도 무방하다. (초기 생성자 부분)

여기에서는 그런 거 신경쓰지 않고, 작업하겠다.


package com.local.example.aop;


import org.springframework.stereotype.Service;


@Service("cal")

public class Calculator {


private long x;

private long y;

private long z;

public Calculator() {

this.x = 1;

this.y = 2;

this.z = 3;

}

public Calculator(long x, long y, long z) {

this.x = x;

this.y = y;

this.z = z;

}

// 작업 원본(A 프로그래머 작성함)

public long sum() {

long result = x + y + z;

System.out.println("비즈니스 로직");

// long d = result / 0; - 일부러 만든 코드(After Throws 보여줄려고)

return result;

}

}



파일명: Calculator.java


[첨부(Attachments)]

Calculator-Aspect.zip


(참고)

주석 친 부분을 주석 풀면, After Throws를 정의한 경우라면 메시지가 출력되는 것을 볼 수 있다.


색깔 칠한 코드는 Calculator(long x, long y, long z) 코드 때문에 Calculator.class 파일로 불러오면 Error를 경험할 수 있다.

그래서 파란색깔로 칠한 코드 Calculator()를 정의해서 문제를 해결한 것이다.




11. AOP 구현(시점 구현) - 시점 예제 (Log.java)


패키지 경로: com.local.example.aop


많은 고민을 한 끝에 간단하면서 실용적인 형태로 코드를 작성하였다.

참고로 시점 정의를 안해도 빌드해보면, HomeController.java에 정의가 잘 되어있으면 돌아가긴 돌아간다.

무슨 말인지는 태스트를 해보면 알 수 있다.


package com.local.example.aop;


import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.After;

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.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Service;


// 관점, 서비스

@Aspect

@Service


// 콤포넌트 사용하지 말것

public class Log {

Logger logger =  LoggerFactory.getLogger(Log.class);

// 섞어적어놓아도 순서를 찾아서 강제 인식함.

    

// 2단계 - 전 단계 시야)

@Before("execution(* com.local.example.aop.Calculator.*(..))")

// @Before("execution(public void sum())")

// 반환값 없어도 무방

    public void logBefore() { 

logger.info("전 단계 관점 - 구현(Before)");

    }

    

// 1단계 - Before보다 전 단계 실행

    // Calculator 클래스의 모든 메서드

// 무조건 반환값이 지정되어야 함. (ProceedingJoinPoint에 대한 Object 반환값 필수 정의되어야 함)

// @Around 이 친구만 Pjp가 있어야 함.

    @Around("execution(* com.local.example.aop.Calculator.*(..))")

    /*@Around("execution(* com.example.demo.controller..*.*(..))")*/

    /*@Around("execution(* com.example.demo..*.*(..))")*/

    public Object logAround(ProceedingJoinPoint pjp) throws Throwable { 

   

logger.info("Around 단계 - 구현(Around)");

Object result = pjp.proceed();

return result;

    }

    

    // 3단계는 (중간) - 임의로 지정해줄 수 있는 것이 아님.

// 4단계: After advice

//@After("execution(* method1())")  -- method1 함수만 실행 

    // (이렇게 하면 안 됨. sum()을 콜하니깐)

    // @After("execution(* method1())")

    @After("execution(* sum())")

public void afterMethod() {

   

    logger.info( "after Method 호출" );

   

}

    

    // 5단계: 맨 마지막 단계

// after-throwing advice /// 오류가 발생할 때 호출함(무조건 보여지는 영역은 아님

    // 쉽게 비유하면, try to catch finally에서 catch 단계로 보면 됨.

    // 오류도 출력되고 after Throwing 로그 메시지도 출력된다.

    // 이 화면을 보려면, 오류나는 코드에 try to catch finally를 적용하면 안 됨.

    // 원본 비즈니스 로직 코드는 그대로 둘 것

    @AfterThrowing(

        pointcut = "execution(* com.local.example.aop.Calculator.sum(..))", 

        throwing = "ex"

    )

public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex) {

logger.info( "after Throwing 호출" + ex.getMessage());

}


    

}


파일명: Log.java


[첨부(Attachments)]

Log.zip





12. AOP 사용시, 핵심사항 - HomeController.java 변경하기


패키지 경로: com.local.example


HomeController.java 코드를 수정할 것이다.


package com.local.example;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;


import com.local.example.aop.Calculator;

import com.local.example.aop.RootConfig;


/**

 * Handles requests for the application home page.

 */

@EnableAspectJAutoProxy

@Controller

public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

/**

* Simply selects the home view to render by returning its name.

*/


@RequestMapping(value = "/", method = RequestMethod.GET)

public String home(Locale locale, Model model) {

logger.info("Welcome home! The client locale is {}.", locale);

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

// Java 방식 - AOP

AnnotationConfigApplicationContext context = 

new AnnotationConfigApplicationContext(RootConfig.class);

// 1. 이전 방식

// Calculator cal = new Calculator(1, 2, 3);


// 2. Aspect 적용

// 소문자로 입력(Calculator -> calculator로)

Calculator cal = (Calculator)context.getBean("cal", Calculator.class);

System.out.printf("result of sum: %d", cal.sum());

model.addAttribute("serverTime", formattedDate );

return "home";

}

}



파일명: HomeController.java


[첨부(Attachments)]

HomeController-aspect.zip




13. 동작 결과 구경하기


두 가지 결과로 작성하였다. 하나는 오류가 없는 코드이다.

하나는 오류가 있어서 After Throws가 호출되는 코드이다.



그림 17. 결과1의 오류 없는 코드(1)



그림 18. 결과1의 오류 없는 코드(2)




그림 19. 결과2의 오류 있는 코드(1)



그림 20. 결과2의 오류 있는 코드(2)





* 맺음글(Conclusion)


AOP 프로그래밍을 실질적으로 쉽게 사용하는 방법에 대해서 소개하였다.



* 참고자료(References)


1. [스프링] Error creating bean with name '***Controller': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named '***Service' is defined 에러 해결방법, https://zzznara2.tistory.com/275, Accessed by 2020-10-04, Last Modified 2015-06-18.


참고: 시중에 있는 AOP 자료를 보고 따라하다보면, 오류 먼저 구경할 것이다. AOP는 조금 어느 정도 프로그래밍 지식이 있을 때 사용하는 걸 권장하고 싶다. (쉽지 않은 부분이다.)


2. Spring : AOP with Java Config - 설정하기와 @Before advice, https://kogle.tistory.com/51, Accessed by 2020-10-04, Last Modified 2020-05-11.


추천(40점): 구축 원리에 대해서 매우 잘 나와있다. 그러나 몇 가지는 수정작업을 해줘야 한다.


3. AspectJ Weaver를 사용한 애노테이션 기반의 스프링 AOP 구현 방법, https://atoz-develop.tistory.com/entry/AspectJ-Weaver%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%95%A0%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-%EA%B8%B0%EB%B0%98%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-AOP-%EA%B5%AC%ED%98%84-%EB%B0%A9%EB%B2%95, Accessed by 2020-10-04, Last Modified 2020-04-27.


추천(25점): 구축 원리를 잘 정리해놨다. 2번 참고자료하고 같이 보는 것을 권장한다. (예제가 살짝 아쉬움)


4. Spring AOP 스프링이 해줄건데 너가 왜 어려워 해? Spring boot에서 aop logging 사용법 제일 쉽게 알려드립니다!, https://jeong-pro.tistory.com/171, Accessed by 2020-10-04, Last Modified 2018-11-23.

반응형

+ Recent posts