[ 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());
    }
}
 

cs




[ 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

+ Recent posts