스프링(Spring) 프레임워크 기본 개념 강좌 (5) - AOP Proxy

 

* 스프링의 핵심 개념

 - 이어서 계속

 

 5) AOP Proxy (AOP 프록시)

 

  5-1) 프록시(Proxy)란?

 

 - 클라이언트가 사용하려고 하는 실제 대상인 것처럼 위장하여 클라이언트 클라이언트의 요청을 받아주어 처리하는 대리자 역할.

프록시의 단어 자체로는 '대리인'이라는 의미를 내포하고 있음. 스프링 AOP에서의 프록시란 말그대로 대리하여 업무를 처리. 함수 호출자는 주요 업무가 아닌 보조 업무를 프록시에게 맡기고, 프록시는 내부적으로 이러한 보조 업무를 처리.

 

이렇게 함으로써, 주 업무 코드는 보조 업무가 필요한 경우, 해당 Proxy 만 추가하면 되고, 필요없게 되면 Proxy를 제거하면 됨.

보조 업무의 탈 부착이 쉬워지고, 그리하여 주 업무 코드는 보조 업무 코드의 변경으로 인해서 발생하는 코드 수정 작업이 필요 없게 됨.

 

 

 

- 프록시의 호출 및 처리 순서 -

1) Proxy 호출
2) 보조 업무 처리
3) Proxy 처리 함수(메서드) 가 실제 구현 함수(메서드) 호출 및 주 업무 처리
4) 제어권이  다시 Proxy 함수(메서드)로 넘어오고 나머지 보조 업무 처리
5) 처리 작업 완료 후, 호출 함수(메서드)로 반환.

 

  5-2) 프록시의 사용 목적

 * 클라이언트가 타깃(Target)에 접근하는 방법을 제어.

 * 타깃에 부가적인 기능을 부여.

 

 (실제 이러한 목적으로 어떻게 사용되는지는 아래에서 보자!)

 

  5-3) 프록시 구현

 

 * 먼저 사칙 연산을 위한 인터페이스(Interface)와 실제 기능을 구현한 클래스(Class) 정의.

// 사칙 연산을 정의하는 인터페이스

package aoptest;

 

 

public interface Calculator {

    public int add(int x, int y);

    public int subtract(int x, int y);

    public int multiply(int x, int y);

    public int divide(int x, int y);

}

 

 

// 사칙 연산을 구현하는 클래스

package aoptest;

 

 

public class myCalculator implements Calculator {

 

   

    @Override

    public int add(int x, int y) {

        return x + y;

    }

 

   

    @Override

    public int subtract(int x, int y) {

        return x – y;

    }

 

   

    @Override

    public int multiply(int x, int y) {

        return x * y;

    }

 

 

    @Override

    public int divide(int x, int y) {

        return x / y;

    }

}

 

 

 

// 실제 위의 사칙연산 클래스를 사용하는 예제 코드

public static void main(String[] args) {

    Calculator cal = new myCalculator(); // 다형성 

    System.out.println(cal.add(3, 4)); // add 메서드를 호출하여 3 + 4 결과를 출력

}

 

 

여기서!!

실제 사칙 연산을 하는데에 있어서 실제 소요되는 시간 측정 이라는 기능이 필요하다고 가정하자!

그렇다면 어떻게 해야 할까?

 

위의 예제 코드에서 cal.add(3, 4) 를 사용하고 있으니, 이 시간 측정을 위한 코드를 일단 myCalculator 클래스의 add 메서드에 추가하여 보자!

 

package aoptest;

 

 

public class myCalculator implements Calculator {

 

   

    @Override

    public int add(int x, int y) {

 

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

 // 보조 업무 (시간 측정 시작 & 로그 출력)

Log log = LogFactory.getLog(this.getClass());

StopWatch sw = new StopWatch();

sw.start();

log.info(“Timer Begin”);

 

 

int sum = x + y; // 주 업무 (덧셈 연산)

 

 

 // 보조 업무 (시간 측정 끝 & 측정 시간 로그 출력)

sw.stop();

log.info(“Timer Stop – Elapsed Time : ”+ sw.getTotalTimeMillis());

 

 

return sum;

    }

 

 

...

 

}

 

 

위와 같이 시간을 측정하기 위한 업무(실제 연산 업무가 아니기 때문에 보조 업무)가 add 메서드에 추가됨.

하지만, 시간 측정을 위한 이러한 코드를 add 메서드 뿐만 아니라, subtract, multiply, divide 메서드에도 추가해 주어야 하고, 설령 측정 방식이 달라지거나 로그 출력 내용이 변경 되기라도 한다면 모든 메서드를 수정해야 한다. 게다가 연산을 위한 주 업무 코드를 수정하는 것도 아니다.

 

 

그렇다면 좀 더 코드를 깔끔하게 하고, 관리도 쉽게 하고, 직관적인 프로그래밍을 위해서는 어떻게 변화를 줄 수 있을까?

바로 방금(또 이전 포스팅에서) 배운 주 업무와 보조 업무를 분리(크로스 컷팅, Cross Cutting)하고 보조 업무를 프록시(Proxy)에게 넘긴다!

 

 

AOP Proxy 를 구현한 예제 코드

// 보조 업무를 처리할 프록시 클래스 정의 (여기서는 LogPrintHandler 라 이름 지었음)

public class LogPrintHandler implements InvocationHandler { // 프록시 클래스 (핸들러)

    private Object target; // 객체에 대한 정보

 

 

    public LogPrintHandler(Object target) { // 생성자

        this.target = target;

    }

 

 

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable   {

        Log log = LogFactory.getLog(this.getClass());

        StopWatch sw = new StopWatch();

        sw.start();

        log.info(“Timer Begin”);

 

        int result = (int) method.invoke(target, args); // (3) 주업무를 invoke 함수를 통해 호출

 

        sw.stop();

        log.info(“Timer Stop – Elapsed Time : ”+ sw.getTotalTimeMillis());

 

        return result;

}

 

 

 

public static void main(String[] args) {

    Calculator cal = new myCalculator();

 

    Calculator proxy_cal = (Calculator) Proxy.newProxyInstance( // (1)

        cal.getClass().getClassLoader(),  // Loader

        cal.getClass().getInterfaces(), // Interface

        new LogPrintHandler(cal)); // Handler (보조 업무를 구현하고 있는 실제 클래스)

 

 

    System.out.println(proxy_cal.add(3, 4));    // (2) 주 업무 처리 클래스의 add 메서드를 호출

}

 

 

 

위의 클래스와 메서드에 대한 설명.

* (1) InvocationHandler 인터페이스를 구현한 객체는 invoke 메소드를 구현해야 함. 
  해당 객체에 의하여 요청 받은 메소드를 리플렉션 API를 사용하여 실제 타깃이 되는 객체의 메소드를 호출해준다. (실제 LogPrintHandler 클래스의 invoke 메서드 내에서 method.invoke(target, args) 메서드를 호출하는데, 이는 주 업무의 메서드를 호출하는 것. main 메서드에서 Proxy.newProxyInstance 를 통해 주 업무를 처리할 클래스(myCalculator)와 보조 업무를 처리할 Proxy 클래스를 결합.

 

  - cal(변수) 실제 객체를 proxy_cal(변수) 객체에 핸들러를 통해서 전달. (LogPrintHandler())

  - getClassLoader() : 동적으로 생성되는 다이내믹 프록시 클래스의 로딩에 사용할 클래스 로더.
  - getInterfaces() : 구현할 인터페이스.
  - LogPrintHandler(cal) : 부가 기능과 위임 코드를 담은 핸들러.

Example)
 Hello proxiedHello = (Hello)Proxy.newProxyInstance(
     getClass().getClassLoader(), -> 동적으로 생성되는 다이내믹프록시 클래스의 로딩에 사용할 클래스 로더
     new Class[] {Hello.class}, <- 구현할 인터페이스
     new UppercaseHandler(new HelloTarget())); -> 부가기능과 위임코드를 담은 핸들러

* (2) 그런다음 주 업무 클래스의 메서드를 호출하게 되면 프록시 클래스의 invoke 메서드가 호출되어 자신의 보조 업무를 처리하고, 주 업무의 메서드를 호출한다.


* (3) invoke() : 메소드를 실행시킬 대상 오브젝트와 파라미터 목록을 받아서 메소드를 호출한 뒤에 그 결과를 Object  타입으로 돌려준다.

[실제 프록시 및 주 업무(타깃) 처리 순서]

 호출 및 처리 순서 : 클라이언트 ---> 프록시 ---> 타깃

 

AOP 개념은 스프링에 한정되어 사용되는 개념이 아님.

실제 위의 코드는 AOP Proxy의 구현(객체를 생성하고, 값을 주입)하는 것을 순수 JAVA 코드 단에서 처리한 것. (스프링 개념 없이)

스프링을 통해서라면 AOP 는 XML과 어노테이션(Annotation)을 통해서 더 쉽게 구현할 수 있음.

 

 



출처: http://ooz.co.kr/201 [이러쿵저러쿵]

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
35 [EMF] EMF Tutorial EMF 튜터리얼 file 졸리운_곰 2023.08.23 283
34 Eclipse RAP Tutorial for Beginners - Workbench Application (OLD) file 졸리운_곰 2021.01.30 323
33 Learn Eclipse GMF in 15 minutes file 졸리운_곰 2019.11.27 253
32 [Eclipse] GEF entry series (10, an implementation of the form) file 졸리운_곰 2019.11.25 212
31 GEF Programmer Guide 번역 졸리운_곰 2019.11.25 227
30 Learn Eclipse GMF in 15 minutes file 졸리운_곰 2019.11.20 224
29 RCP 에디터 정리 졸리운_곰 2019.11.20 333
28 다른 그림과 관련하여 GEF 편집기 레이아웃에서 그림의 위치 제한 조건을 동적으로 계산 Dynamically calculating the position constraints for a figure in a GEF editor layout in relation to another figure file 졸리운_곰 2019.11.20 277
27 RCP 등에서 .mf 파일로 다른 프로젝트 익스포트 포함시 라이브러리(메소드)를 찾지 못할 때, Eclipse RCP - cant resolve importing libraries in final build file 졸리운_곰 2019.10.15 410
26 ESE2006-EclipseModelingSymposium15_GMF.pdf file 졸리운_곰 2019.09.21 302
25 GMF_Creation_Review.pdf file 졸리운_곰 2019.09.21 366
24 Eclipse EMF and GMF Tutorial file 졸리운_곰 2019.09.21 222
23 GMF Tutorial/ko file 졸리운_곰 2019.09.20 347
22 Model Driven Architecture approach to domain of graphical editors file 졸리운_곰 2019.09.20 268
21 Single_Sourcing_RAP_RCP_en.pdf file 졸리운_곰 2019.05.15 311
20 Rich client platform 설명 및 배우기 참고 졸리운_곰 2019.05.15 309
19 Rich Ajax Platform, Part 1: 소개 file 졸리운_곰 2019.05.15 320
18 또 하나의 크로스 플랫폼: Eclipse RAP file 졸리운_곰 2019.05.15 319
17 Eclipse 4 RCP 튜토리얼(완료) file 졸리운_곰 2019.05.14 977
16 Updating UI in Eclipse RCP 졸리운_곰 2015.11.07 408
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED