[ AOP( Aspect Oriented Programming ]
:: Spring이 아니고 방법론 AOP를 구현할때 Spring이 도움을 준다.
:: 주 업무로직 외에 사용자가 모르는 개발자나 운영자가 개발이나 운영을 위해서 만든 부가적인 코드들이 있다
그래서 관점에 따라서 나누어 만들게 된다.
::관점들에 대해서 분류하고 결합을 어떻게 해야할지의 방법론
:: 주 업무로직의 처음 끝 부분에 로그,보안,트랜잭션처리 등을 넣지 않고
프록시처럼 만들어 이걸 통해서 사용하도록 만드는 것.
:: java만으로도 구현 가능
[Core Concern]
:: 주 업무로직
[Corss-cutting Concern]
:: 로그처리, 보안처리, 트랜잭션처리 등등..
[ Spring 을 사용하지 않고 AOP 작성 ]
< 과거 로직 >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class JavaExam Implements Exam{ public int total(){ long start = System.currentTimeMillis(); SimpleDateFormat dayTime = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss"); String str = dayTime.format(new Date(start)); /* ------------------------------------- */ int result = kor + eng + math + com; /* ------------------------------------- */ long end = System.currentTimeMillis(); String message = (end-start)+"ms가 걸림"; System.out.println("message"); return result; } |
< AOP 로직 >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Exam proxy = (Exam) Proxy.newProxyInstance( JavaExam.class.getClassLoader() , new Class[]{Exam.class} , new InvocationHandler(){ /* Corss-cutting Concern */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ /* Corss-cutting Concern */ return null; } int total = proxy.total(); float avg = proxy.avg(); }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package spring.aop; import jdk.jshell.execution.LoaderDelegate; import spring.aop.entity.Exam; import spring.aop.entity.NewlecExam; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Program { public static void main(String[] args){ Exam exam = new NewlecExam(1,1,1,1); //여기부터 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(); // 곁다리 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",exam.total()); } } |
[ Spring 을 사용하고 AOP 작성 ]
<보조업무 형태>
:: 원하는 업무형태를 인터페이스 상속받아 구현해서 넣으면 aop프로그램이 됨
@ Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package spring.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import spring.aop.entity.Exam; public class Program { public static void main(String[] args){ ApplicationContext context = new ClassPathXmlApplicationContext("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()); } } |
@ XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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.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> |
1. Around Advice
:: 앞,뒤 모두 보조업무
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package spring.aop; 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; } } |
2. Before Advice
:: 앞부분만 보조업무
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package spring.aop; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class LogBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("앞에서 실행될 로직"); } } |
3. After returnning Advice
:: 뒷부분만 보조업무
1 2 3 4 5 6 7 8 9 10 11 12 13 | package spring.aop; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class LogAfterReturningAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("returnValue:"+returnValue + ", method:"+method.getName()); } } |
4. After Throwing Advice
:: 예외처리 보조업무
1 2 3 4 5 6 7 8 9 10 | package spring.aop; import org.springframework.aop.ThrowsAdvice; public class LogAfterThrowingAdvice implements ThrowsAdvice { public void afterThrowing(IllegalArgumentException e)throws Throwable{ System.out.println("예외가 발생하였습니다.:"+ e.getMessage()); } } |
[ PointCut and JoinPoint and Weaving ]
< PointCut >
:: 기본적으로 Target으로 생각하는 내용이 있으면 Proxy는 Target을 대상으로 모든 메서드를 JoinPoint로 생각한다.
때문에 이를 개별적으로 설정할 수 있는 역할을 함.
* 방법 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <bean id="classicPointCut" class="org.springframework.aop.support.NameMatchMethodPointcut" > <property name="mappedName" value="total"/> <!--total메서드만 지정--> </bean> <bean id="classBeforeAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" > <!--포인트컷과 프록시를 연결해주는 역할을 advisor가 한다.--> <property name="advice" ref="logBeforeAdvice"/><!--setter인데 이름은 정해져 있다--> <property name="pointcut" ref="classicPointCut" /><!--setter인데 이름은 정해져 있다.--> </bean> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="target"/> <property name="interceptorNames"> <list> <value>logAroundAdvice</value> <!--<value>logBeforeAdvice</value>--> <value>classBeforeAdvisor</value> <!-- advisor의 id를 적어준다--> <value>logAfterReturningAdvice</value> <value>LogAfterThrowingAdvice</value> </list> </property> </bean> |
*방법2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //패턴없이 value값 넣는 방법 <bean id="classBeforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <!--포인트컷과 프록시를 연결해주는 역할을 advisor가 한다.--> <property name="advice" ref="logBeforeAdvice"/> <property name="mappedNames"> <!-- 포인트컷 사용할 수 있는 value가 여러개일 경우 사용--> <list> <value>total</value> <value>avg</value> </list> </property> <property name="mappedName" value="avg" /> <!-- 포인트컷 사용할 수 있는 value가 하나일 경우 사용--> </bean> //패턴(정규식)을 이용한 방법 <bean id="classBeforeAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="logBeforeAdvice" /> <property name="patterns"> <list> <value>.*to.*</value> </list> </property> </bean> | cs |
< JoinPoint >
:: 연결할 지점(메서드 등..)을 의미함.
< Weaving >
:: 뜨개질처럼 서로를 연결해주는 과정을 의미함.
'프로그래밍 > Spring' 카테고리의 다른 글
Properties파일 읽기 (0) | 2020.05.22 |
---|---|
intellij Spring MVC & Gradle 프로젝트 생성 (0) | 2020.05.22 |
Spring MVC & Gradle & Mariadb 연동 (0) | 2020.05.21 |
SpringMVC_Annotation (0) | 2020.05.20 |
파일 다운로드 (0) | 2018.10.24 |