Dev/Spring

Spring3.0 - AOP

창문닦이 2019. 4. 17. 18:26

OOP(Object Oriented Programming : 객체지향프로그래밍)

객체지향 프로그래밍이란 인간 중심적 프로그래밍 패러다임. 현실 세계의 사물들을 객체라고 보고 그 객체로부터 개발하고자 하는 애플리케이션에 필요한 특징들을 뽑아와 프로그래밍 하는 것이다. 이것을 추상화라한다. OOP 로 코드를 작성하면 이미 작성한 코드에 대한 재사용성이 높다. 

 AOP(Aspect Oriented Programming : 관점지향프로그래밍) 

문제를 바라보는 관점을 기준으로 프로그래밍하는 기법. 문제를 해결하기 위한 핵심 관점 사항과 전체에 적용되는 공통 관심사항을 기준으로 프로그래밍 함으로써 공통 모듈을 여러코드에 쉽게 적용할 수 있도록 도와준다.

 

불특정 다수의 객체(클래스,메소드)에 코드를 탈착할 수 있게 만드는 기능.

공통적으로 사용되는 부분(공통화해서 라이브러리 할수있는 부분 트랜젝션이나 에외부분)을 별도로 분리하는 기술이다.

 

① Advice : 언제 공통 관심 기능을 핵심 로직에 적용할지를 정의한다. 

② Joinpoint : Advice를 적용 가능한 지점을 의미한다. 메서드 호출, 필드 값 변경 등이 Joinpoint에 해당

③ Pointcut : Joinpoint의 부분 집합으로써 실제로 Advice가 적용되는 Joinpoint를 나타낸다. 스프링에서는 정규 표현식이나 AspectJ의 문법을 이용하여 Pointcut를 정의할 수 있다.  before(전) after(후) around(전후) return(정상처리시) throwable(에러발생시)

④ Weaving : Advice를 핵심 로직 코드에 적용하는 것을 weaving 이라고 한다. 즉, 공통 코드를 핵심 로직 코드에 삽입하는 것

⑤ Aspect : 여러 객체에 공통으로 적용되는 공통 관심 사항을 Aspect이라고 한다. 트랜잭션이나 보안등이 Aspect 예이다.

1. 프로젝트 생성 (Spring Legacy Project - Spring Utility Project)

2. AOP를 쓰기 위해 4개의 라이브러리 설치 

- Spring AOP

- AspectJ Runtime

- AspectJ Weaver

- Code Jeneration Library

- pom.xml 작성

- 메이븐을 통하여 물리적 파일이 저장된 경로 확인

 

3. target 객체 생성 - ① TargetA 클래스

package com.exe.aop;

import org.springframework.stereotype.Component;

@Component("targetA")

public class TargetA {

//이 메소드들이 Advice를 적용하면 target들이 됨

public void doSomething1() {

System.out.println("TargetA.doSomethis1");

}

 

public void doSomething2() {

System.out.println("TargetA.doSomethis2");

}

 

public void doAnother1() {

System.out.println("TargetA.doAnother1");

}

 

public void doAnother2() {

System.out.println("TargetA.doAnother2");

}

}

3. target 객체 생성 - ② TargetB 클래스

package com.exe.aop;

import org.springframework.stereotype.Component;

@Component("targetB")

public class TargetB {

//이 메소드들이 Advice를 적용하면 target들이 됨

public void doSomething1() {

System.out.println("TargetB.doSomethis1");

}

 

public void doSomething2() {

System.out.println("TargetB.doSomethis2");

}

 

public void doAnother1() {

System.out.println("TargetB.doAnother1");

}

 

public void doAnother2() {

System.out.println("TargetB.doAnother2");

}

}

4. advice 클래스 생성 - ① MyBeforeAdvice 

package com.exe.aop;

public class MyBeforeAdvice {//수행할 작업

//특정 조인포인트에 적용(실행)할 코드 실행시점에 따라 Before Advice, After Advice 등으로 구

//advice : 이 어드바이스를 어디에 적용할지 P/C를 정할 것

public void beforeMethodCall(){

System.out.println("Jointpoint 메소드가 실행되기 전에...");

}

}

4. advice 클래스 생성 - ② MyAfterAdvice 

package com.exe.aop;

public class MyAfterAdvice {

public void afterMethodCall() {

System.out.println("Jointpoint 메소드가 실행된 후에..");

}

}

5. app-context.xml  bean 객체 생성

Spring 2 부터는 AOP 설정과 관련된 "aop" 네임스페이스 및 "aop" 네임스페이스와 관련된 XML 스키마가 추가 되었다. "aop"네임스페이스와 관련된 XML 다음과 같이 <beans> 태그에 명시할 수 있다.

<?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:context="http://www.springframework.org/schema/context"

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

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

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

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

https://www.springframework.org/schema/context/spring-context-3.0.xsd

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

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

<description>Example configuration to get you started.</description>

<context:component-scan base-package="com.exe.aop" />

 

<!-- execution(public void com..aop.*.*(..)) -->

<!-- execution(메소드의접근지정자 반환값 패키지명.클래스.메소드(매개변수))  -->

 

<!-- 객체 생성. 어노테이션으로 생성해도 문제 없음 -->

<bean id="beforeAdvice" class="com.exe.aop.MyBeforeAdvice"/>

 

<aop:config>

<aop:aspect ref="beforeAdvice">

<aop:pointcut id="beforePointCut" expression="execution(public void com..aop.*.*(..))" />

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

</aop:aspect>

</aop:config>

</beans>

어드바이스를 어디에 적용할 것인지 포인트컷을 만들고자 한다. - before(전) after(후) around(전후) return(정상처리시) throwable(에러발생시) 

 

<aop:pointcut id="beforePointCut" expression="execution(public void com..aop.*.*(..))" />

public : 메소드의접근지정자 

void : 반환값

com..aop.*.*(..) : 패키지명(가운데명은 생략됨. '..'과 '*'은 일맥상통).클래스명.메소드명(매개변수) ) .. 의 의미는 생략이란 표현

 

<aop:aspect ref="beforeAdvice">

com.exe.aop.MyBeforeAdvice클래스를 객체생성하여 advice로 적용할 것이다.

 

 expression="execution(public void com..aop.*.*(..))"

적용되는 모든 패키지의 모든클래스의 모든 메소드.(매개변수 있든없든 다같이)

 

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

 aop:before :  advice를 언제 적용할지는 메소드가 실행되기 전으로 할 것이고 실행되는 어드바이스의 메소드는 beforeMethodCall이다.

 

Pointcut의 종류

6. AopMain 클래스 생성

package com.exe.aop;

import org.springframework.context.support.GenericXmlApplicationContext;

public class AopMain {

public static void main(String[] args) {

 

GenericXmlApplicationContext context = new GenericXmlApplicationContext("app-context.xml");

TargetA ta = (TargetA)context.getBean("targetA");

ta.doAnother1();

ta.doAnother2();

ta.doSomething1();

ta.doSomething2();

 

TargetB tb = (TargetB)context.getBean("targetB");

tb.doAnother1();

tb.doAnother2();

tb.doSomething1();

tb.doSomething2();

}

}

실행 화면

8개의 메소드가 실행되기전의 시점(before pointcut)에서 어드바이스의 메소드가 실행되는 것을 조회

특정 클래스의 메소드만 실행되게 조건 설정 가능1 

메소드명이 do로 시작하고 1로 끝나는 경우에 적용

특정 클래스의 메소드만 실행되게 조건 설정 가능2

메소드명 중간에 S가 들어가고 1로 끝나는 경우에 적용

Before & After 동시 설정 가능

실행 화면


Around 적용 예제

1. AroundAdvice 클래스 생성 (메소드 전/후 실행)

package com.exe.aop;

import org.aspectj.lang.ProceedingJoinPoint;

public class MyAroundAdvice {

 

public Object aroundMethodCall(ProceedingJoinPoint jointPoint) {

Object result = null;//메소드가 실행됨에 따라 반환값의 자료형을 모르므로 Object

 

try {

System.out.println("JointPoint 메소드 실행전..(Around)");

result = jointPoint.proceed();//메소드 실행

System.out.println("JointPoint 메소드 실행후..(Around)");

} catch (Throwable e) {

 

}

return result;

}

}

2. app-context.xml 작성 - bean객체 생성

<bean id="aroundAdvice" class="com.exe.aop.MyAroundAdvice"/>

<aop:config>

<aop:aspect ref="aroundAdvice">

<aop:pointcut id="aroundPointcut" expression="execution(public void com..aop.*A.*Some*(..))" />

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

</aop:aspect>

</aop:config>

3. 실행 화면

 


 

AfterReturning 적용 예제

1. AfterReturningAdvice 생성 (정상 처리시 실행)

package com.exe.aop;

public class MyAfterReturningAdvice {

public void afterReturningMethodCall() {

System.out.println("JointPoint 메소드가 정상 실행한 뒤에..");

}

}

2. app-context.xml - bean객체 생성

<bean id="afterReturningAdvice" class="com.exe.aop.MyAfterReturningAdvice"></bean>

<aop:config>

</aop:aspect> -->

<aop:aspect ref="afterReturningAdvice">

<aop:pointcut id="afterReturningPointcut" expression="execution(public void com..aop.*.*A*1(..))" />

<aop:after-returning method="afterReturningMethodCall" pointcut-ref="afterReturningPointcut"/>

</aop:aspect>

</aop:config>

3. 실행 화면

 


 

AfterThrowing 적용 예제

1. AfterThrowingAdvice 클래스 생성(에러 발생시 실행 )

package com.exe.aop;

public class MyAfterThrowingAdvice {

public void afterThrowingMethodCall() {

System.out.println("JointPoint 메소드가 에러 발생했을때..");

}

}

2. app-context.xml - bean객체 생성

<bean id="afterThrowingAdvice" class="com.exe.aop.MyAfterThrowingAdvice"/>

<aop:config>

<aop:aspect ref="afterThrowingAdvice">

<aop:pointcut id="afterThrowingPointcut" expression="execution(public void com..aop.*.*(..))" />

<aop:after-throwing method="afterThrowingMethodCall" pointcut-ref="afterThrowingPointcut"/>

</aop:aspect>

</aop:config>

3. 실행 화면

 


Advice 정의 관련 태그 요약

<aop:before> : 메서드 실행 전에 적용되는 Advice를 정의 한다.

<aop:after-returning> : 메서드가 정상적으로 실행된 후에 적용되는 Advice를 정의 한다.

<aop:after-throwing> : 메서드가 예외를 발생 시킬때 적용되는 Advice를 정의 한다.

<aop:after> : 메서드가 정상적으로 실행하거나, 예외가 발생되는지의 여부에 상관없이 적용되는 Advice를 정의 한다.

<aop:around> : 메서드 호출 이전, 이후, 예외 발생 등 모든 시점에 적용 가능한 Advice를 정의 한다.

app-context.xml - bean객체 생성

<bean id="beforeAdvice" class="com.exe.aop.MyBeforeAdvice"/>

<bean id="afterAdvice" class="com.exe.aop.MyAfterAdvice"/>

<bean id="aroundAdvice" class="com.exe.aop.MyAroundAdvice"/>

<bean id="afterReturningAdvice" class="com.exe.aop.MyAfterReturningAdvice"/>

<bean id="afterThrowingAdvice" class="com.exe.aop.MyAfterThrowingAdvice"/>

<aop:config>

<aop:aspect ref="beforeAdvice">

<aop:pointcut id="beforePointCut" expression="execution(public void com..aop.*.*(..))" />

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

</aop:aspect>

<aop:aspect ref="afterAdvice">

<aop:pointcut id="afterPointCut" expression="execution(public void com..aop.*.*(..))" />

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

</aop:aspect>

<aop:aspect ref="aroundAdvice">

<aop:pointcut id="aroundPointcut" expression="execution(public void com..aop.*.*(..))" />

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

</aop:aspect>

<aop:aspect ref="afterReturningAdvice">

<aop:pointcut id="afterReturningPointcut" expression="execution(public void com..aop.*.*(..))" />

<aop:after-returning method="afterReturningMethodCall" pointcut-ref="afterReturningPointcut"/>

</aop:aspect>

<aop:aspect ref="afterThrowingAdvice">

<aop:pointcut id="afterThrowingPointcut" expression="execution(public void com..aop.*.*(..))" />

<aop:after-throwing method="afterThrowingMethodCall" pointcut-ref="afterThrowingPointcut"/>

</aop:aspect>

</aop:config>

실행 화면

 


ANNOTATION을 이용한 AOP 구현

1. app-context.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:context="http://www.springframework.org/schema/context"

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

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

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

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

https://www.springframework.org/schema/context/spring-context-3.0.xsd

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

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

<description>Example configuration to get you started.</description>

<context:component-scan base-package="com.exe.aop" />

<aop:aspectj-autoproxy/>

</beans>

AspectJ 관련 Annotation을 사용하기 위해서 XML에 기본 설정 

<aop:aspectj-autoproxy/>

 

2-1. Before advice 클래스 - 메서드 실행 전에 적용되는 Advice

package com.exe.aop;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.springframework.stereotype.Component;

//@Aspect @Component객체 틀만들고 ref까지 가져온 것

@Aspect

@Component

public class MyBeforeAdvice {//수행할 작업

//특정 조인포인트에 적용(실행)할 코드 실행시점에 따라 Before Advice, After Advice 등으로 구현

 

//advice : 이 어드바이스를 어디에 적용할지 P/C를 정할 것

@Before("execution(* com..aop.*.*(..))")

public void beforeMethodCall(){

System.out.println("Jointpoint 메소드가 실행되기 전에...");

}

}

2-2. Around advice 클래스 - 메서드 호출 이전, 이후, 모든 시점에 적용

package com.exe.aop;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;

 

@Aspect

@Component

public class MyAroundAdvice {

 

@Around("execution(* com..aop.*.*(..))")

public Object aroundMethodCall(ProceedingJoinPoint jointPoint) {

Object result = null;//메소드가 실행됨에 따라 반환값의 자료형을 모르므로 Object

 

try {

System.out.println("JointPoint 메소드 실행전..(Around)");

result = jointPoint.proceed();//메소드 실행

System.out.println("JointPoint 메소드 실행후..(Around)");

} catch (Throwable e) {

// TODO: handle exception

}

return result;

}

}

2-3. AfterReturning advice 클래스 - 메서드가 정상적으로 실행된 후에 적용

package com.exe.aop;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;

 

@Aspect

@Component

public class MyAfterReturningAdvice {

@AfterReturning("execution(* com..aop.*.*(..))")

public void afterReturningMethodCall() {

System.out.println("JointPoint 메소드가 정상 실행한 뒤에..");

}

}

2-4. After advice 클래스 - 메서드가 정상 실행 or 예외 발생 여부에 상관없이 적용

package com.exe.aop;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;

@Aspect

@Component

public class MyAfterAdvice {

@After("execution(* com..aop.*.*(..))")

public void afterMethodCall() {

System.out.println("Jointpoint 메소드가 실행된 후에..");

}

}

2-5. AfterThrowing advice 클래스 - 메서드가 예외를 발생 시킬때 적용

package com.exe.aop;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;

@Aspect

@Component

public class MyAfterThrowingAdvice {

@AfterThrowing("execution(* com..aop.*.*(..))")

public void afterThrowingMethodCall() {

System.out.println("JointPoint 메소드가 에러 발생했을때..");

}

}

3. 실행 화면

 

'Dev > Spring' 카테고리의 다른 글

Spring3.0 - MVC web & MyBatis  (0) 2019.04.18
Spring3.0 - MVC web & JDBC 게시판만들기  (0) 2019.04.18
Spring3.0 - ORM(MyBatis)  (0) 2019.04.17
Spring3.0 - DAO(JDBC)  (0) 2019.04.16
Spring3.0 MVC 예제(2)  (0) 2019.04.16