AOP 방법론으로 프로그래밍하면 어떤 도움을 받을 수 있는지 알아보기
AOP(Aspect Oriented Programming) 이해하기
관점 지향 프로그래밍
사용자 요구사항을 수반하기 위해서 주 업무 로직이 아닌 필요한 코드가 들어가게 된다.
사용자는 모르는 내용으로 개발자가 개발을 위해서 운영자가 운영을 위해서 넣게 된다.
사용자가 바라보았던 내용 - > 주 업무
운영자의 관점으로 봤던 내용 추가 -> 새로운 로직
더 큰 단위로 관점을 분리하고 결합시켜서 프로그램을 만들 것인가 하는 방법론
Concern
Primary(Core) Concern과 Cross-cutting Concern
사용자의 요구사항을 수반하기 위해서 필요한 로직 -> Cross-cutting Concern
로그 처리
보안 처리
트랜잭션 처리
Core Concern은 주 업무만 만들고
Cross-cutting Concern과 관련된 Concern을 Core Concern에 두지 않고 따로 proxy에 두고 호출
겉 업무를 따로 분리해서 겉 업무를 Core Concern에서 분리사용
Spring에서 AOP를 이용하면 코드의 변경과 수정의 문제가 Spring DI로 해결된다.
AOP 코드 구현하기
총점과 평균을 구하는 예제
업무단위 만들어주기
업무 호출하기
사용자가 요구하는 기능 수준에서 total을 출력했다.
개발자 관점에서 새로운 관점을 추가해야 한다. -> 얼마나 느린지 알아보기 위해 시간 체크 코드 넣기
겉 업무에 해당하는 관점이 다른 사람들의 필요에 의해 만들어지는 코드이다.
NewlecExam.java
package spring.aop.entity;
public class NewlecExam implements Exam {
private int kor;
private int eng;
private int math;
private int com;
//생성자
public NewlecExam() {
// TODO Auto-generated constructor stub
}
//생성자 오버로드
public NewlecExam(int kor, int eng, int math, int com) {
super();
this.kor = kor;
this.eng = eng;
this.math = math;
this.com = com;
}
public int getKor() {
return kor;
}
public void setKor(int kor) {
this.kor = kor;
}
public int getEng() {
return eng;
}
public void setEng(int eng) {
this.eng = eng;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getCom() {
return com;
}
public void setCom(int com) {
this.com = com;
}
@Override
public int total() {
// long start = System.currentTimeMillis();
int result = kor+eng+math+com;
//일부러 시간을 느리게 해준다.
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// long end = System.currentTimeMillis();
//
// String message = (end - start) + "ms 시간이 걸렸습니다.";
// System.out.println(message);
return result;
}
@Override
public float avg() {
float result = total() / 4.0f;
return result;
}
@Override
public String toString() {
return "NewIecExam [kor=" + kor + ", eng=" + eng + ", math=" + math + ", com=" + com + "]";
}
}
하지만 지금 하는 것은 옛날 버전으로 코드 안에 작성하지 않고 불러오는 방법을 사용해야 한다.
순수 자바로 AOP 구현하기
Proxy 도구 사용하기
겉 업무를 필요에 따라 사용할 수 있다. -> AOP 방식
Program.java
package spring.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import spring.aop.entity.Exam;
import spring.aop.entity.NewlecExam;
public class Program {
public static void main(String[] args) {
Exam exam = new NewlecExam(1,1,1,1);
//Proxy가 겉업무를 포함해서 exam을 호출
//newProxyInstance(실질적인객체, 인터페이스 정보(배열), 겉업무를 추가시키는 부분 InvocationHandler())
Exam proxy = (Exam)Proxy.newProxyInstance(NewlecExam.class.getClassLoader(),
new Class[] {Exam.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
//method.invoke(업무객체, )
Object result = method.invoke(exam, args);
long end = System.currentTimeMillis();
String message = (end - start) + "ms 시간이 걸렸습니다.";
System.out.println(message);
return result;
}
}
);
System.out.printf("total is %d\n", proxy.total());
System.out.printf("avg is %f\n", proxy.avg());
}
}
스프링으로 AOP 구현하기
모든 설정을 xml에서 처리 Spring Around Advice
3가지 결합되는 관계 설정
target
LogAroundAdvice
proxy
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: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="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="target" />
<property name="interceptorNames">
<list>
<value>logAroundAdvice</value>
</list>
</property>
</bean>
</beans>
LogAroundAdvice.java
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;
}
}
Program.java
package spring.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring.aop.entity.Exam;
import spring.aop.entity.NewlecExam;
import spring.di.NewlecDIConfig;
public class Program {
public static void main(String[] args) {
ApplicationContext context =
//new AnnotationConfigApplicationContext(NewlecDIConfig.class);
new ClassPathXmlApplicationContext("spring/aop/setting.xml");
Exam proxy = (Exam)context.getBean("proxy");
System.out.printf("total is %d\n", proxy.total());
System.out.printf("avg is %f\n", proxy.avg());
/*
Exam exam = new NewlecExam(1,1,1,1);
//Proxy가 겉업무를 포함해서 exam을 호출
//newProxyInstance(실질적인객체, 인터페이스 정보(배열), 겉업무를 추가시키는 부분 InvocationHandler())
Exam proxy = (Exam)Proxy.newProxyInstance(NewlecExam.class.getClassLoader(),
new Class[] {Exam.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
//method.invoke(업무객체, )
Object result = method.invoke(exam, args);
long end = System.currentTimeMillis();
String message = (end - start) + "ms 시간이 걸렸습니다.";
System.out.println(message);
return result;
}
}
);
*/
}
}
Spring xml 방식 AOP
주 업무 내용만 동작하게 하기 - 설정만으로 로그를 뺐다 붙였다 할 수 있다.