관리 메뉴

나만의공간

스프링 주요 개념 용어 3 - AOP(Aspect-oriented programming) 본문

IT/Spring

스프링 주요 개념 용어 3 - AOP(Aspect-oriented programming)

밥알이 2014. 6. 9. 17:21

아래는 해당 블로그에서 가져온 글입니다.

http://blog.naver.com/acatholic/90176627945


AOP(aspect-oriented programming) 

 

aspect : feature of something ,특징 

여기서는 그냥 특정 클래스의 특징. 관심사 정도로 번역하면 될 듯함.

(특정 클래스의) 원래 모습, 원래 특징, 원래 기능. 원래 관심사

 

결국 스프링에서 AOP 란 여러개의 클래스들이 각각의 고유한 관심사에만 집중하도록

공통으로 쓰이는 로그관련모듈, 트랜잭션관련모듈,jdbc커넥션 관련 모듈등은 

모두 다른 각각의 클래스에서 객체생성하게 하지 말고, 스프링에서 객체 생성하고

관리하게 하는 것.

 

- AOP 는 주로 트랜젝션 관리와 보안 서비스에 사용됨.

- 템플릿을 사용해서 반복사용되는 어구(boilerplate code) 를 제거함.

--> 스프링은 템플릿 안에 자주 사용되는 코드를 은닉화함으로써 반복사용코드를 제거한다.

POJO 에선 주로 jdbc 연결, 커넥션 반납, 종료코드에 사용.

 

1. 정의

:

AOP 는 종종 소프트웨어 시스템안에서

'관심사의 분리'(관심의 분리) 을 촉진하는 기술로 정의된다. 

 

 

 

 

2. 개념

:

소프트웨어는 고유한 기능을 가진 컴포넌트들로 구성된다.

그런데 각 컴포넌튿르은 종종 자기 자신의 고유한 기능의 범위를 벗어나는 기능을 수행하게 되기도 한다.

 

학생명단만을 관리하는 고유기능을 가진 클래스에서 그 본래 고유한 관심사인 학생명단 관리뿐 아니라 로그관리나 트랜잭션관리도 할 수 밖에 없는 경우가 많다.

 

또, 교직원 명단 관리가 주요 관심사인 클래스에서도 그 본래 고유한 관심사에서 벗어나는 로그관리나 트랜잭션관리도 할 수 밖에 없는 경우도 역시 많다.

 

로그관리 모듈이나 트랜잭션 관리 모듈들이 로깅서비스 안에서만 사용되는게 아니라는 얘기. 위에서처럼 학생명단 관리 모듈에서도 사용되고 교직원 명단 관리 모듈에서도 사용된다.

 

본래 각 클래스가 갖고 있는 일차적인 관심사가 아닌 다른 관심사도 다루어야 하는게 합리적이지 않고, 관리에도 손이 많이 가기때문에 여러 클래스에서 쓰일수 있는 모듈들은 스프링 컨테이너가 관리하도록 하자는 것(예를 들면, 교직원 명단 관리 클래스에서 로그관리 클래스 객체 생성하고 메소드 호출하지 말고 스프링이 로딩될 때 읽어들이는 xml 파일에 관련 내용을 추가해서 스프링 컨테이너가 로깅 모듈들이나 jdbc 커넥션 관련 모듈들을 관리하게 하자는 것)

 

결국 AOP 는 특정 클래스가 자신의 클래스만의 기능만 표현하도록 해준다.

 

상기 내용을 이미지로 표현하면 아래와 같다.



위에서 보듯 왼쪽의 각 서비스들에 로깅, 보안, 트랜잭션 기능은 강사든 학생이든 (강의)컨테츠서비스든 각 서비스의 

일차적인 관심사는 아님. 그러나 로깅, 보안, 트랜잭션모듈들은 왼 쪽의 각 서비스에 산재해있음(각 서비스들이 로깅,보안등의 모듈들을 참조하고 있음)

 

이를 보완하기 위해 스프링에서 공통 모듈들을 관리하게 되면 아래 그림처럼 됨.

AOP 를 이용함으로써, 시스템 전반적인 관심사(로깅 ,보안, 트랜잭션등)를 갖는 모듈들이 그들이 영향을 끼치는 (다른)컴포넌트들(학생, 학과과정서비스등등)을 모두 덮어 버리고 이로써 학생서비스등 각각의 서비스들은 그들의 고유한 기능에 집중할 수 있게 됨.

 

 


 

 

 

 

3. 스프링에서의 구현

:

스프링에서 AOP 는 DI 정의한 xml 파일 안에 AOP 정의를 추가하면 됨.

 

예를 들어 어느 서비스에서나 똑같이 로깅 역할하는 클래스를 aop 라고  xml 파일에 기술하여 스프링에 알려주기만 하면

로그 남기는 다른 모든 클래스의 각 소스레벨에서 관리할 필요는 없다는 것. 

각 클래스들의 고유한 주요 관심사에 각각 집중할 수 있게 해준다.

 

- xml 파일에는 bean  엘리먼트의 하위 엘리먼트인 aop 엘리먼트를 이용하여 aop 로 지정할 클래스의 특정 메소드 수행전과 수행후 실행될 메소드를 지정해 주면 된다.

 

 

- 앞의 게시글에서 작성했던 용감한기사 클래스를 예로 들어본다.

앞서 작성 했던 클래스는 아래와 같다.

 

package com.springinaction.knights;

public class BraveKnight implements Knight {

private Quest quest;

public BraveKnight(Quest quest) {

this.quest = quest;

}

public void embarkOnQuest() throws QuestException {

quest.embark();

}

 

}


이 클래스는 DI 를 적용하여 xml 에 작성한 후 아래와 같이 호출하게 코딩했었다.

package com.springinaction.knights;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class KnightMain {

public static void main(String[] args) {

ApplicationContext context =

new ClassPathXmlApplicationContext("knights.xml");

Knight knight = (Knight) context.getBean("knight");

knight.embarkOnQuest();

}

}


위의 코드에서 knight.embarkOnQuest(); 를 호출하기 직전과 직후에 로그 확인을 위해 콘솔에 출력문을 찍고 싶다고 하자. 

이를 위해 아래와 같이 Minstrel(중세음악가) 이라는 로그관리 클래스를 만든다.

 

package com.springinaction.knights;

public class Minstrel {

public void singBeforeQuest() {

System.out.println("Fa la la; The knight is so brave!");

}

public void singAfterQuest() {

System.out.println(

"Tee hee he; The brave knight did embark on a quest!");

}

 

}


위 Minstrel(중세음악가) 클래스에 있는 각 메소드들은 단순히 콘솔에 출력하는 역할을 한다.

그러나, 아래와 같이 호출하면 BraveKnight  클래스안에서  작성한 코드가 BraveKnight  클래스 고유의 관심사에  집중되지 않고 로그관리 클래스까지 관리하게 된다(로그관리용Minstrel 클래스를 자신 클래스에서 선언한 변수에 담았으므로 관리개념 들어가게 됨)

 

package com.springinaction.knights;

public class BraveKnight implements Knight {

private Quest quest;

private Minstrel minstrel;

public BraveKnight(Quest quest, Minstrel minstrel) {

this.quest = quest;

this.minstrel = minstrel;

}

public void embarkOnQuest() throws QuestException {

minstrel.singBeforeQuest();

quest.embark();

minstrel.singAfterQuest();

}

 

}

 


만약, 시스템을 고도화하는 중에 로그가 필요하다면 개발장비에서 위와 같은 코드로 수정하고 테스트를 해도 무방하지만 그렇다고 해도 단순히 콘솔에 출력하는 코드가 필요한 모든 클래스를 위와 같은 방식으로 수정하는건 비효율적임.


이럴 때, 스프링에 Quest 인터페이스의 embark() 메소드를 호출하는 모든 부분에 

embark() 메소드 호출직전에 Minstrel 클래스의 singBeforeQuest() 를 호출하여 로그를 남기고

embark() 메소드 호출직후에 Minstrel 클래스의 singAfterQuest() 를 호출하여 로그를 남기라고 알려주면 된다.

이렇게 하면 결과적으로 로그 관리 클래스 Minstrel 클래스를 만들고 아래 xml 파일만 만들면 

기존 코드들은 수정하지 않은 상태에서 모든 클래스의 로그가 필요한 부분에 출력문을 넣어줄수 있다. 

 

 

 

xml 파일은 아래와 같이 된다. 파란색 부분은 앞의 게시글에서 작성했던 DI 관련 엘리먼트들임.

검은색이 aop 관련 코드들. 빨간색은 편의상 넣은 주석임.


<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

<bean id="knight" class="com.springinaction.knights.BraveKnight">

<constructor-arg ref="quest" />

</bean>

<bean id="quest"

class="com.springinaction.knights.SlayDragonQuest" />

<bean id="minstrel"

class="com.springinaction.knights.Minstrel" />  <!-- 코드단에서 객체 생성하지 않고 스프링이 객체생성하도록 하고 싶은 클래스라고 bean 태그이용해 알려줌 ,minstrel 클래스의 객체를 생성하고 소멸될 때가지 관리하라고 스프링에 전달함 -->

<aop:config> <!-- 아직 bean 엘리먼트가 끝나지 않았음에 주목. 이 minstrel 빈을 aop 로 사용하겠다고 선언한다.-->

<aop:aspect ref="minstrel">  

<aop:pointcut id="embark"

expression="execution(* *.embarkOnQuest(..))" />  <!-- 기준이 되는 메소드는  embarkOnQuest 메소드이고 이 메소드는 embark 로 이 aop 엘리먼트 안에서 부르겠다고 선언-->

<aop:before pointcut-ref="embark"

method="singBeforeQuest"/>  <!-- embarkOnQuest() 메소드 수행전에는Minstrel 클래스의  singBeforeQuest() 메소드를 호출하라고 지시-->

<aop:after pointcut-ref="embark"

method="singAfterQuest"/>  <!-- embarkOnQuest() 메소드 수행 후에는Minstrel 클래스의  singAfterQuest() 메소드를 호출하라고 지시-->

</aop:aspect>

</aop:config>

</beans>

 

 

 

 

아래는 http://blog.naver.com/leeyoon0607/70141613967 에서 가져온 글


Comments