본문 바로가기
자바과정/스프링

스프링 AOP(자바 방식, Spring XML 방식)

by Parkej 2021. 4. 8.

출처 : www.youtube.com/watch?v=y2JkXjOocZ4&list=PLq8wAnVUcTFVUMCKI4CL_EHWW5ykPnL0z

 

** Annotation 방식은 다음에 따로 정리하겠습니다.

 

AOP란 (Aspect Oriented Programming)
관점 지향 프로그래밍 
 - 사용자 중심인 객체 지향 프로그래밍에서 좀 더 큰 틀인 관점 지향 프로그래밍이라고 합니다.
 - 기존엔 사용자가 원하는 업무 기반의 로직에만 관심을 가졌었지만, 사용자의 요구사항말고 이 요구사항을 수반하기 위해 코드들을 작성하다보니 그 외의 코드가 들어가게 됨을 느낍니다.

(개발자/관리자가 프로그램을 구현하기 위해서든 테스트하기 위해서든 필요한 코드들이 존재하게 됨.)

- 사용자 관점으로 봤떤것이 지금까지 객체지향으로 잘 만들어 졌다면, 추가로 만들게 되는 로직을 개발자/운영자 관점에서 넣어야하는 로직이 있어야함.
- 이걸 관점 지향 업무라 함. (객체지향보다 큰 개념)
- 주 업무 로직 : 객체지향, 그 외의 것까지 포함 : 관점 지향


- Primary(Core) Concern : 관점에 해당되는 것중에서 주 관심사에 해당되는 것들은 객체로 만들어짐, 실질적인 업무들은 메소드로 만들어짐

- cross-cutting : 관점이 다른로직
- 주업무 로직과 뺏다 꽂았다가 자유로워야 함.
- 보안처리 : 권한을 줄수도 뺄수도있어야함.
- 로그처리 : 남겼다 뺏다 지웠다..
- 과거 커팅작업이 쉽지않아 직접 지우거나,, 주석처리,,, 소스를 가지고 잇는 사람만이 할 수 있고 재배포에 불편함을 느꼈습니다.



그래서 이 방법을 쉽게 해보려고 생각해낸게 AOP 방법론이라고 합니다.

그림 출처.... 구글링...... 주소를 잃어버렸씁니다.

 

- 주 업무 로직 분리(Core Concern) , 개발자가 처리 방식을 따로 생성 (cross cutting Concern)



바로 따로 공부한 강의 코드들로 보여드리겠습니다.

 

자바코드 관점지향 방식
더보기
자바 방식

 

실행결과

 

프록시 개념
- 실제 주 업무를 갖고 있는 녀석을 호출해주는 그러한 역할을 함.
- 사용자는 주업무로직을 직접 호출하는게 아니라 프록시를 호출하게 됨.
- 프록시에서 앞뒤로 개발자가 원하는 코드를 삽입

 

 

 

스프링 방식의 AOP
- 스프링을 이용하면 이것을 자유롭게 구현이 가능함.
- 파일 구성

 

 

Program.java
public class Program {

	public static void main(String[] args) {
		
		ApplicationContext context = new ClassPathXmlApplicationContext("spring/aop/setting.xml");
		// ApplicationContext context = new AnnotationConfigApplicationContext(NewlecAppConfig.class);
		
		Exam exam = context.getBean("exam",Exam.class);
		
		System.out.printf("total is %d\n", exam.total());
		System.out.printf("avg is %f\n", exam.avg()); 
        }
}

LogAroundAdvice
- implements MethodInterceptor (작업 전 후로)

(코어 컨서 실행전)
LogBeforeAdvice
- implements MethodBeforeAdvice

(반환 값을 가지고 할것이 있다면)
logAfterReturning 결과값을 반환한다음 이어서 작업할게 있으면 ..
- implements AfterReturningAdvice

LogAfterThrowingAdvice
- implements ThrowsAdvice 어떤 예외가 발생하느냐에 따라 함수의 인자가 달라짐

 

LogAroundAdvice
package spring.aop.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

// 주 업무 로직의 앞 뒤로 생성
public class LogAroundAdvice implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		
		long start = System.currentTimeMillis();
		
		Object result = invocation.proceed();
		
		long end = System.currentTimeMillis();
		String message = (end - start) + "ms 시간이 걸렸다.";
		System.out.println(message);
		
		return result;
	}

}

 

 

 

 

LogBeforeAdvice
package spring.aop.advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

// 주 업무 로직의 앞에서만 실행이 됨.
public class LogBeforeAdvice implements MethodBeforeAdvice{

	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {

		
		System.out.println("앞에서 실행될 로직");
	}


}

 

 

 

 

LogAfterReturningAdvice
package spring.aop.advice;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

// 주 업무 로직의 결과값을 이용하여 ..
public class LogAfterReturningAdvice implements AfterReturningAdvice{

	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("returnValue:"+returnValue + ", method:"+method.getName());
	}

}

 

 

 

 

LogAfterThrowingAdvice
package spring.aop.advice;

import org.springframework.aop.ThrowsAdvice;

// 예외가 발생했을 시.
public class LogAfterThrowingAdvice implements ThrowsAdvice{
	public void afterThrowing(IllegalArgumentException e) throws Throwable{
		System.out.println("예외가 발생하였습니다.: " + e.getMessage());
	}
	
}





 

- Spring AOP 용어

 AOP는 프록시를 갖고있음
- 포인트 컷(Pointcuts) : total() 메서드만 위빙이 됐음 좋겠다. (별도의 메서드만 호출)
- 조인 포인트(JoinPoint) : 프록시는 타겟을 대상으로 모든 메서드를 조인포인트라 생각함.조인하게될 메서드 포인트
- 위빙(weaving) : 프록시와의 연결과정

org.springframework.aop.support.NameMatchMethodPointcut
- 네임이란것을 기준으로 하는 포인트 컷
- total, avg : advice 별로 포인트 컷 사용 가능

org.springframework.aop.support.DefaultPointcutAdvisor
- 포인트 컷과 어드바이스를 연결해주는 역할

 

 

setting.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:p="http://www.springframework.org/schema/p"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">


	<bean id="target" class="spring.aop.entity.NewlecExam" p:kor="1" p:eng="1" p:math="1" p:com="1" />
    <!-- 곁다리업무를 하는 핸들러 -->
	<bean id="logAroundAdvice" class="spring.aop.advice.LogAroundAdvice" /> 
	<bean id="logBeforeAdvice" class="spring.aop.advice.LogBeforeAdvice" />
	<bean id="logAfterReturningAdvice" class="spring.aop.advice.LogAfterReturningAdvice" />
	<bean id="logAfterThrowingAdvice" class="spring.aop.advice.LogAfterThrowingAdvice" />
	
	<!-- 
	<bean id = "classicPointCut" class = "org.springframework.aop.support.NameMatchMethodPointcut">
		<property name="mappedName" value = "total" />
	</bean>
	 -->
	<!-- <bean id="classicBeforeAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		 <property name="advice" ref="logBeforeAdvice"/>
		 <property name="pointcut" ref="classicPointCut"/>
	</bean>
	
	<bean id="classicAroundAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		 <property name="advice" ref="logAroundAdvice"/>
		 <property name="pointcut" ref="classicPointCut"/>
	</bean> -->
	
<!-- 	<bean id="classicBeforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
		 <property name="advice" ref="logBeforeAdvice"/>
		 <property name="mappedNames">
		 	<list>
		 		<value>total</value>
		 		<value>avg</value>
		 	</list>
		 </property>
	</bean> -->
    
    <!-- 간소화된 advisor -->
	<bean id="classicBeforeAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		 <property name="advice" ref="logBeforeAdvice"/>
		 <property name="patterns">
		 	<list>
		 		<value>.*to.*</value>
		 	</list>
		 </property>
	</bean>
	
	<bean id="classicAroundAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
		 <property name="advice" ref="logAroundAdvice"/>
		 <property name="mappedName" value = "total"/>
	</bean>
	
	<!-- 프록시 생성 -->
	<bean id="exam" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="target" />  <!-- name 프록시 세터, ref target 레퍼런스 -->
		<property name="interceptorNames">
			<list>
				<value>classicAroundAdvisor</value>
				<value>classicBeforeAdvisor</value>
				<value>logAfterReturningAdvice</value>
				<value>logAfterThrowingAdvice</value>
			</list>
		</property>
	</bean>


</beans>

spring AOP 실행결과

반응형

댓글