본문 바로가기

[Spring]

[Spring]11월 11일 Spring 설정 파일(xml) 기반 AOP 설정 예제

● 설정파일기반 AOP 설정.

- XML 스키마 확장기법을 통해 설정파일을 작성한다.


● AOP 설정 태그


1. <aop:config> : aop설정의 root 태그, Aspect 설정들의 묶음

2. <aop:aspect> : Aspect 설정 - 하나의 Aspect 설정

Aspect가 여러 개일 경우 <aop:aspect> 태그가 여러 개 온다.

3. <aop:pointcut> : Advice에서 참조할 pointcut 설정

4. Advice 설정태그들

A. <aop:before> - 메소드 실행 전 실행될 Advice

B. <aop:after-returning> - 메소드 정상 실행 후 실행될 Advice

C. <aop:after-throwing> - 메소드에서 예외 발생시 실행될 Advice

D. <aop:after> - 메소드 정상 또는 예외 발생 간관없이 실행될 Advice - finally

E. <aop:around> - 모든 시점에서 적용시킬 수 있는 Advice 구현


★ 예제

핵심관심사항에 대한 정의만 갖고 있는 Person 인터페이스

핵심관심사항에 대해 게임을 하도록 구현된 Boy 클래스

핵심관심사항에 대해 화장을 지우도록 구현된 Girl 클래스

공통관심사항을 구현할 MyAspect클래스


Animal 인터페이스

package aop5;


public interface Animal {

public void doSomething();

}



Cat

package aop5;


public class Cat implements Animal{

public void doSomething(){

System.out.println("들어오던지 말던지 신경안쓴다");

}

}



Dog

package aop5;


public class Dog implements Animal{

public void doSomething(){

System.out.println("꼬리를 흔들며 반긴다");

}

}



MyAspect

package aop5;


public class MyAspect {

public void before(){

System.out.println("주인을 기다린다");

System.out.println("주인이 집에 들어온다");

}

public void after(){

System.out.println("밥을 맛있게 먹는다");

}

public void after_returning(){

System.out.println("밥을 준다");

}

public void after_throwing(){

System.out.println("밤새 운다");

}

}


스프링 설정 파일을 만든다. applicationContext.xml

만든후 Namespaces 에서 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-4.2.xsd

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

<bean id="cat" class="aop5.Cat"></bean>

<bean id="dog" class="aop5.Dog"></bean>

<bean id="myAspect" class="aop5.MyAspect"></bean>

<aop:config>

<aop:pointcut expression="execution (public void aop5.*.doSomething())" id="pt"/>

<aop:aspect ref="myAspect">

<aop:before method="before" pointcut-ref="pt"/>

<aop:after-returning method="after_returning" pointcut-ref="pt"/>

<aop:after-throwing method="after_throwing" pointcut-ref="pt"/>

<aop:after method="after" pointcut-ref="pt"/>

</aop:aspect>

</aop:config>


</beans>



위 설정파일에 대해 설명하자면..


타겟클래스랑 공통관심사항이 적용된 클래스의 객체를 빈으로 등록해준다.

<aop:config>

이 안에다가 pointcut이 어떤 함수호출인지 pointcut 전/후/정상후/에러후 에 어떤 공통관심사항을 엮을건지

advice들을 aspect로 등록 하자!

예를들자면..↓

<aop:before method="before" pointcut-ref="pt"/>

위에놈은 pointcut으로 지정된 메소드 호출 전에 before() 라는 메소드 호출!

이런식으로 after-returning ....쭉쭉 써내려 간것이다.

</aop:config>



<aop:pointcut expression="이곳에 포인트컷 표현식을 이용해서 특정메소드가 호출되는 상황을 작성" id="pt"/>


POJO 기반 AOP구현 - AspectJ 표현식


● 표현

명시자(패턴)

-패턴은 명시자 마다 다름.

예) execution(public * abc.def..*Service.set*(..)

패턴문자

-  * : 1개의 모든 값을 표현

argument에서 쓰인 경우 : 1개의 argument

package에 쓰인 경우 : 1개의 하위 package

이름(메소드, 클래스)에 쓰일 경우 : 모든 글자들

- .. : 0개 이상

argument에서 쓰인 경우 : 0개 이상의 argument

package에 스인 경우 : 0개의 이상의 하위 package


execution

- execution(수식어패턴? 리턴타입패턴 패키지패턴?.클래스명패턴.메소드명패턴(argument패턴))

- 수식어패턴 : public, protected, 생략

- argument에 type을 명시할 경우 객체 타입은 fullyName으로 넣어야 한다.

java.lang은 생략가능

- 위 예 설명

적용하려는 메소드들의 패턴은 public 제한자를 가지며 리턴 타입에는 모든 타입이 다 올 수 있다.

이름은 abc.def 패키지와 그 하위 패키지에 있는 모든 클래스 중 Service로 끝나는 클래스들에서

set으로 시작하는 메소드이며 argument는 0개 이상 오며 타입은 상관 없다.


어라운드 어드바이스(around advice) 사용해서도 해보자.

around를 사용하시려면 MyAspect를 조금바꿔 줘야한다.

MyAspect

package aop6;


import org.aspectj.lang.ProceedingJoinPoint;


public class MyAspect {


public void around(ProceedingJoinPoint pj){

System.out.println("주인을 기다린다");

System.out.println("주인이 집에 들어온다");

try{

pj.proceed();

System.out.println("밥을 준다");

}

catch(Throwable e)

{

System.out.println("밤새 운다");

}

System.out.println("밥을 맛있게 먹는다");

}

public void before(){

System.out.println("주인을 기다린다");

System.out.println("주인이 집에 들어온다");

}

public void after(){

System.out.println("밥을 맛있게 먹는다");

}

public void after_returning(){

System.out.println("밥을 준다");

}

public void after_throwing(){

System.out.println("밤새 운다");

}

}

around라는 함수를 만들어서 매개변수로 JoinPoint의 하위 클래스인 ProceedingJoinPoint를 지정하고,

pj.proceed() =  pointcut으로 지정해준 메소드를 불러준다




설정파일에서 는

<?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-4.2.xsd

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

<bean id="boy" class="aop5.Boy"></bean>

<bean id="girl" class="aop5.Girl"></bean>

<bean id="myAspect" class="aop5.MyAspect"></bean>

<aop:config>

<aop:pointcut expression="execution (public void aop5.*.doSomething())" id="pt"/>

<aop:aspect ref="myAspect">

<aop:around method="around" pointcut-ref="pt"/>


</aop:aspect>

</aop:config>

</beans>




이제 설정파일을 작성했으니 테스트를 해볼 테스트 클래스를 만들어서 불러 보자.


package aop5;


import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;


public class Test {


public static void main(String[] args) {

ApplicationContext context 

= new FileSystemXmlApplicationContext("src/aop5/applicationContext.xml");

//파일시스템 경로를 통해 xml파일 찾는아이

Animal a = context.getBean("dog", Animal.class); //동적 바인딩에 의한 위빙이 일어나야 되기때                                                                                     문에 부모타입으로!

a.doSomething();

}


}




출처 : 삼성SDS멀티캠퍼스

강사 : 홍승길

Email : iccack70@gmail.com