1. Implementing AOP in Spring
저자 :Manoj Debnath
작성일 : 2013년 2월 25일
번역 : 황미애 주임, 손성관 사원
번역일 : 2013년 3월 24일
원문주소 :http://www.developer.com/java/implementing-aop-in-spring.html
관점 지향 프로그래밍은 줄곧 Spring Framework의 기본적인 요소였다. Spring 개발자들
에게 이 프로그래밍 모델은 낮은 수준의 구조로 알려졌기 때문에 다소 복잡하게 사용되
어왔다.아마도, 이런 이유로 Spring AOP 프로그래밍은 고급개발자들에게 사용되지 않았
다. 최근 Spring과 AOP의 발전 등 많은 변화가 있었다. 이 글에서 AOP에 대한 기본적인
설명과, AOP에서 구현하는 방법을 이야기해보겠다.시간이 조금 걸릴 수 있겠지만 직접
따라 해보도록 하자.
함수형 프로그래밍
함수형 프로그래밍의 경우, 해결해야 할 문제들은 함수 단위로 나누어지는데, 각 함수들
은 특정한 단위 작업을 수행한다. 각 함수는 함수 호출을 통해 다른 함수와 대화한다. 전
체적인 개념은 함수 모듈의 결합에서 문제영역을 분리하는 것이다.
이제, 함수 호출의 복잡한 네트워크의 환경을 상상해보자. 스파게티 코드1 한 그릇을 얻
는다.
그림 1 Spaghetti code
1
스파케티코드 : 매우 복잡하고 얽힌 특정 소스에 코드 대한 경멸 용어
(http://en.wikipedia.org/wiki/Spaghetti_code )
2. 객체지향 프로그래밍
OOP에서는 어플리케이션을 설계하는 사고 과정에서부터 패러다임의 변화가 일어난다.
상이한 작업들은 단위 함수로 설계되기 보다는 개별 객체로서 설계되는데, 이는 문제 영
역 내의 개별적인 개체들을 반영하는 것이다.
설계 결과로, 복잡했던 코드는 우려했던 것들로부터의 분리로 깔끔해졌지만..
몇 가지 문제점들이 지속된다.
모든 작업들이 객체로 분류 될 수 없거나 업무적 측면을 고려하지 않은 채 구현
하는 상황이 발생했다.
메시지를 로깅하는 것과 같이 몇몇 혹은 모든 객체에서 사용되는 일반적인 하위
기능을 생각해보자. 이 기능을 구현하기 위해 LogMessage를 기록하려는 각 객체
의 멤버 함수를 정의하거나 LogMessage가 있는 별도의 Logger클래스를 정적/비
정적 멤버 함수로 만들 수있다. 그렇게 상속받거나, 새로운 Logger 객체를 생성
하거나, 단순하게 정적 멤버 함수를 호출하거나, Spring을 통해 dependency
injection2 기능을 사용하여 프로그래머가 원하는 방법으로 사용할 수 있다.
어떤 방법을 이용하건 간에, 말한 바와 같이 디자인 하는 것 이 아주 좋은 생각인 것은
아니다. 위의 경우, 실무에서 가장 많이 사용되는 객체가 실제로 가장 하찮은 것으로 보
인다. Logger객체는 업무적 측면을 고려하지 않는다. 이는 객체의 상호작용에만 관심을
보일 뿐이다.
OOP는 여전히 괜찮지만 모듈방식의 또다른 방법을 찾기위해 cross-custting concern의
완전한 분리가 요구되었다.
2
dependency injection : 소프트웨어 구성요소에 외부 종속성을 공급하는 안전한 방법
(http://en.wiktionary.org/wiki/dependency_injection)
3. 관점 지향 프로그래밍
AOP는 OOP의 모듈화 패러다임을 완전히 새로운 수준으로 올려놓았다. AOP는 Aspect 3
라고 하는 새로운 모듈화 단위를 도입함으로써 cross-cutting concern이라는 개념을 분리
해 냈다. Aspect는 특정한 cross-cutting 기능성에 초점을 맞추고 있으며 어플리케이션
의 핵심 비즈니스 클래스에 횡단 관심사를 부가하지 않는다. 이는 weaving이라 하는 프
로세스를 통해 핵심 클래스와 crosscutting aspect를 결합하여 최종 시스템을 구성하는
aspect weaver에 의해 처리된다. AOP는 OOP를 개조했다고 할 수 있는데, 이를 통해 설
계, 구현 및 유지보수가 쉽게 이루어질 수 있다.
Spring Framework에서의 AOP
Spring의 핵심 영역은 dependency injection, enterprise service의 추상화와 관점지향 프
로그래밍이다. dependency injection은 선언 방식에서 외부 구성 요소가 완벽히 작동하는
응용프로그램에 연결할 수 있도록 해주며, enterprise service의 추상화는 변경 가능한 기
반 코드로부터 안정된 응용프로그램 로직을 분리하고 AOP는 비즈니스 로직으로부터
cross-cutting concerns의 구현을 분리한다. 이렇게 세가지가 잘 결합되어 Spring이라는
강력한 솔루션을 제공한다.
Aop implementing in Spring
소프트웨어 의존성 :
Aspectj4 프로그래밍을 하기 위해선 아래라이브러리들이 필요하다.
-AspectJ : AspectJ 컴파일러는모든 버전의 자바 플랫폼에 대한 프로그램을 생성하긴 하
지만 실행 자체는 Java2를(1.4 이거나 그 이상) 이 필요하다.
- Cglib : 코드 생성 라이브러리, 런타임 상황에서 자바 클래스를 상속받거나 인터페이스
를 구현하기 위해 사용된다.
- Aopalliance :Guice5나 Spring 같은 여러 프레임워크에서 사용하는 인터페이스의 집합.
- asm : 모든 유형의 자바 바이트 코드 조작 및 이진 형태로 직접 기존 클래스를 수정하
3
aspect : 컴퓨터 공학에서 프로그램의 aspect란, 프로그램의 다른 많은 영역에 연결되어 있는 기
능이지만, 프로그램의 주요 기능엔 연결되어 있지 않다.
(http://en.wikipedia.org/wiki/Aspect_(computer_programming)
4
AspectJ :자바 프로그래밍 언어에 PARC에서 만든 관심 지향 확장이
다.(http://en.wikipedia.org/wiki/AspectJ)
5
Guice :Google Guice는 구글에서 만든 의존성 주입(Dependency Injection) 디자인 패턴의 자바 구
현이다.
(http://en.wikipedia.org/wiki/Google_Guice)
4. 거나 동적으로 클래스를 생성하는 데 사용되는 분석 프레임워크.
스프링 프레임워크를 위해서는 아래 라이브러리들이 필요하다.
- Spring : 오픈 소스 어플리케이션 프레임워크, 플랫폼을 위한 IoC 컨테이너
- Common-logging : 로그정보 라이브러리
Java SE와 Eclipse ( 참고 : 다른 IDE를 사용해도 되지만 여기서는 Eclipse를 사용)
Configuring Your Project for AOP
Java SE와 이클립스를 설치한다. 이클립스에서 다음과 같은 jar와 다음과 같이 라이브러
리를 포함하고 사용자 라이브러리를 작성한다.
Aspect 사용자 라이브러리를 만들고 해당 jars파일을 import한다.
1. aopalliance-x.x.x.jar
2. cglib-nodep-x.x.x.jar
3. aspectjrt.jar, aspectjweaver.jar (aspect-x.x.x.jar 를 압축해제 하면 두 파일을 얻을 수 있다.)
4. asm-x.x.jar
Spring 사용자 라이브러리를 생성하고 해당 jars파일을 include한다.
1. commons-loggin.x.x.x.jar
2. spring-framework-x.x.x.dist 에 있는 모든 jar파일들
이클립스에서 사용자 라이브러리 작성을 한번 완료하면 당신은 aspectj 기능을 포함 하
는 다른 프로젝트에 라이브러리를 재 사용할 수 있다.
참고 : 사용자 라이브러리는 이클립스에 Windows - > Preference,
Expand Java -> Build Path - > User Libraries 설정 창 왼쪽 목록에서 생성 할 수 있다.
5. Examples
해당 예제는 4개의 클래스를 포함한다 : 직원, 부서 모델 클래스, 어플리케이션의 주요
시작지점과 LoggingAspect 클래스 Aspect들이 그것이다.
packageorg.simpleaop.model;
publicclass Employee {
private String name;
...
//Getters and Setters
}
packageorg.simpleaop.model;
publicclass Department {
private String location;
...
//Getters and Setters
}
Main 클래스는 스프링의 의존성 주입을 나타낸다.
packageorg.simpleaop.app;
//...import statements
publicclass Main {
publicstaticvoid main(String[] args) {
ApplicationContext context = newClassPathXmlApplicationContext("spring.xml");
Employee emp = context.getBean("employee", Employee.class);
emp.setName("Jerry Mouse");
Department dept = context.getBean("department", Department.class);
dept.setLocation("Disney Land");
System.out.println("Name :"+emp.getName());
System.out.println("Department :"+dept.getLocation());
}
}
6. 설정 파일 spring.xml은 의존성 주입과 AOP 설정을 나타낸다.
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-
beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-
2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<aop:aspectj-autoproxy/>
<beanname="employee"class="org.simpleaop.model.Employee"/>
<beanname="department"class="org.simpleaop.model.Department"/>
<beanname="loggingAspect"class="org.simpleaop.aspect.LoggingAspect"/>
</beans>
LoggingAspect 클래스는 스프링의 AOP 구현을 보여준다. 이 클래스는 @Aspect 어노테
이션이 추가되어 있는 단순한 POJO 일 뿐이다. 이 클래스 안에서 @Before, @After,
@Within, @Around, @Pointcut 등등 하나 이상의 여러 Advice(advice는 AOP의 어노테이
션6으로 시작하는 함수에 AOP용어이다.)를 원하는 대로 사용 할 수 있다.
packageorg.simpleaop.aspect;
//..import statements
@Aspect
publicclassLoggingAspect {
@Before("execution(public String getName())")
publicvoidbeforeAdvice(){
System.out.println("Before advice. Runs before the function called");
}
//...other advices
}
6
Annotation :주석은 자바 컴퓨터 프로그래밍 언어로, 자바 소스 코드에 추가 할 수 있는 구문 메타
데이터의 한 형태이다.
(http://en.wikipedia.org/wiki/Java_annotation)
7. @Before 어노테이션은 단순히 모든 public String getName() 함수가 실행되기 전에
beforeAdvice advice를 실행을 의미한다.
다음은 @Before 어노테이션의 또 다른 변형 방법이다.
@Before("execution(publicString org.simpleaop.Employee.getName())")
다른점은 advice가 Employee클래스의 getName메소드의 실행 전에 실행 된다는 것이다.
와일드카드(*)의 이용 :
@Before("execution(public * get*())")
public 펑션이고 리턴 타입에 무관하고, 인자가 없으며, 메소드명이 'get'으로 시작되는
경우 호출된다.
@Before("execution(public * get*(..))")
public 펑션이고 리턴 타입에 무관하고, 인자가 없거나 있을 수 있으며 메소드명이 'get'
으로 시작되는 경우 호출된다.
@Before("execution(public * get*(*))")
public 펑션이고 리턴 타입에 무관하고 인자가 하나 이상 존재하며 메소드명이 'get'으로
시작되는 경우 호출된다.
좀더 많은 예제와 설명은 Spring aspect-oriented programming 관심지향 프로그래밍 문
서를 참조 할 것.
AOP Usage
AOP가 매우 유용한 상황들이 있는데, 가장 일반적인 경우는 로깅과 프로파일링이다.
- 요청 메소드가 동작하고 있을 때 @Around advice 묶어 주면 트랜젝션을 실패 했을 때
즉시 롤백 할 수 있기 때문에 AOP는 트랜젝션 관리에 매우 유용할 수 있다.
- 접근제어 또는 보안 메커니즘을 @Before advice와 같이 구축하게 되면 누군가가
이 기능을 사용하기 전에 접근자격을 확인 할 수 있다.
- 비즈니스 메소드가 예외를 발생 시킬 때 예외 래핑을 할 수 있다. @After throwing
advice는 상황을 처리할 때 활용할 수 있다. 예를 들어 모든 DAO계층에서 데이터엑세스
익셉션을 처리하지않고 모든 SQLException을 포장하여 서비스계층에서 발생시키길 원하
8. 는 경우에 사용 할 수 있다.
AOP는 수 많은 용도로 사용될 수 있다. 위의 인용은 단지 빙산의 일각일 뿐이다.
마무리
스프링은 enterprise application에서 가장 선호되는 경량 프레임워크이다.
proxy 디자인패턴과 인터셉터 기반인 AOP 시스템은 enterprise application의 요구사항을
충족시킬 부분을 포함하고 있다. Spring2.0이전의 Spring AOP는 현재보다 더 복잡했었다.
AspectJ를 기반으로 한 새로운 프로그래밍 모델은 더 나은 프로그래밍환경을 제공하고,
프로그래머가 더 나은 코드를 작성하고 사용자정의를 손쉽게 할 수 있다. 의존성주입과
AOP에 대한 개념을 명확히 가지고 있다면, AOP를 이용한 Spring 어플리케이션 개발 방
법을 빠르게 익힐 수 있을 것 이다.