강좌/Spring 3.0

009. AOP 일단 덤벼 보자 - 실전편

여름나라겨울이야기 2013. 1. 22. 18:08
728x90

지난 시간에 Boy.java, Girl.java 를 만들어서 횡단관심사항과 핵심관심사항이 무엇인지를 살펴 보았습니다.

 

그럼 여기서는 일단 AOP 적용을 위해 Boy.java 만 바꾸어 보도록 하겠습니다.

Spring AOP 를 쉽게 적용하기 위해서는 인터페이스 기반으로 Boy.java 를 변경하는 것이 유리합니다

(굳이 안해줘도 되긴 하지만 많이 귀찮습니다.  인터페이스 만드는 것이 오히려 편합니다.  상세한 내용은 제 AOP 강좌 이후에 스프링 인 액션, 토비의 스프링 등등을 강츄합니다.)

 

aop002 패키지를 만들었습니다.

 

IPerson 이라는 인터페이스를 추가했습니다.

 

package aop002;

public interface IPerson {
 void housework();
}

 

IPerson 을 구현하도록 Boy.java 를 변경했습니다.  그리고 핵심관심사항이 아닌 횡단관심사항을 깡끄리 지웠습니다.  오오.. 이 간결한 코드를 보라.

 

package aop002;

public class Boy implements IPerson {
 public void housework() {
  System.out.println("컴퓨터로 게임을 한다.");
 }
}

 

Start.java 를 Spring 프레임워크 기반에서 구동될 수 있도록 변경했습니다.

 

package aop002;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

 

public class Start {
 public static void main(String[] args) {
  ApplicationContext context = new FileSystemXmlApplicationContext("/src/main/java/aop002/expert.xml");
  
  IPerson romeo = (IPerson)context.getBean("boy");
  
  romeo.housework();
 }
}

 

그리고 expert.xml 을 생성해야 겠죠.

 

<?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/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 <aop:aspectj-autoproxy /> 
 
 <bean id="myAspect" class="aop002.MyAspect" />
 <bean id="boy" class="aop002.Boy" />

</beans>

 

오웃 처음 보는 코드도 있고 myAspect 라고 하는 bean 이 설정되어 있습니다.

 

당황하지 마시고 expert.xml 을 열고 소스코드 하단의 Namespace 탭을 클릭해서 aop 부분을 체크해 주시면 위에 빨간 세줄이 자동으로 완성이 됩니다.  다시 Source 탭으로 돌아와서

 

 <aop:aspectj-autoproxy />

<bean id="myAspect" class="aop002.MyAspect" />
<bean id="boy" class="aop002.Boy" />

이 세 줄을 입력해주시면 되겠죠.

 

그럼 aop002.MyAspect.java 의 코딩을 보시죠.

 

package aop002;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.JoinPoint;

 

@Aspect
public class MyAspect {
 @Before("execution(public void aop002.Boy.housework())")
 public void before(JoinPoint joinPoint){
  System.out.println("얼굴 인식 확인: 문을 개방하라");
  //System.out.println("열쇠로 문을 열고 집에 들어간다.");
 }
}

 

간단하게 처리하기 위해 애너테이션을 사용했습니다.

 

@Aspect 는 이 클래스는 이제 AOP 에서 사용하도록 하겠다.

@Befor 는 주어진 메소드의 실행 전에 이 메소드를 실행하겠다.

JoinPoint 는 @Before 에서 선언된 메소드 즉 aop002.Boy.housework() 를 의미합니다.

 

오호 정상 구동된다면 이제 열쇠로 문을 열고 집에 들어가는 것이 아니라 스프링 프레임워크가 사용자를 인식해서 자동으로 문을 열어주게되겠군요.. 오오 최첨단의 세상에 오신 것을 환영합니다.

 

자자.. 다 입력하셨으면 저장 확인 하시고 Start.java 의 Context Menu > Run As > Java Application

그럼 결과가...

 

INFO : org.springframework.context.support.FileSystemXmlApplicationContext - Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@a981ca: startup date [Tue Jan 22 17:42:47 KST 2013]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from file [C:\workspace_spring\ExpertSpring30\src\main\java\aop002\expert.xml]
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@12b7eea: defining beans [org.springframework.aop.config.internalAutoProxyCreator,myAspect,boy]; root of factory hierarchy
얼굴 인식 확인: 문을 개방하라
컴퓨터로 게임을 한다.

 

이렇게 나오면 얼마나 행복하시겠습니까마는.. ^^;

 

INFO : org.springframework.context.support.FileSystemXmlApplicationContext - Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@8814e9: startup date [Tue Jan 22 15:27:21 KST 2013]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from file [C:\workspace_spring\ExpertSpring30\src\main\java\aop002\expert.xml]
INFO : org.springframework.context.annotation.ClassPathBeanDefinitionScanner - JSR-330 'javax.inject.Named' annotation found and supported for component scanning
Exception in thread "main" java.lang.NoClassDefFoundError: org/aspectj/weaver/BCException
 at java.lang.Class.getDeclaredMethods0(Native Method)
 at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)

 

중략...

 

 at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:84)
 at aop002.Start.main(Start.java:8)
Caused by: java.lang.ClassNotFoundException: org.aspectj.weaver.BCException
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
 ... 13 more

 

이렇게 나온다는 거.. ㅡㅡ;

 

큰 문제는 아니지만 구글링을 제대로 안 하시면 몇 일 밤을 새고서 "이거였어!!!!" 하면서 긴 한숨이 나오는 에러죠.  ^^

저희가 설치했던 STS 에 추가적인 작업을 해주지 않았기에 발생하는 오류인데요.

 

간단히 조치 하자면 이렇게 하시면 됩니다.  잘 살펴 보시면 프로젝트 폴더 구조에서 pom.xml 파일을 찾으실 수 있는데요.

 

  <!-- AspectJ -->
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>${org.aspectj-version}</version>
  </dependency> 
  
  <!-- Logging -->

 

위에 부분을 찾아 아래처럼 내용을 추가 후에 저장해 주시고 다시 Start.java 의 Context Menu > Run As > Java Application 해주시면 예쁜 실행 결과를 보실 수 있습니다.

 

  <!-- AspectJ -->
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>${org.aspectj-version}</version>
  </dependency> 
  
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.6.11</version>
  </dependency>
  
  <!-- Logging -->

 

STS 를 더 완벽하게 미리 더 셋팅하고 싶으신 분들은 http://erlka.tistory.com/161 를 참조해 보셔도 좋겠군요.  단, 저는 안했습니다. ^^

 

이번 강좌에 대한 설명 문서는 다음 강좌에 만들도록 하겠습니다.

반응형