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


1) AOP 개념설명


[횡단관심사]

모든 영역에 공통적으로 적용되는 코딩

어플리케이션 여러부분에 영향을 주는 기능.


그림처럼 1XX3을 찾으라고 하면 앞이 1인 15,10의 3번을 모두 검사한다.

그림처럼 횡단으로 검사하는 모습을 볼 수 있다.


[JointPoints]

애플리케이션 실행의 특정 지점을 의미

AOP에서 Aspect(횡단 관심사)를 적용하는 위치를 표시하는데 사용


[Advice]

특정 조인포인트에 적용(실행)할 코드

실행시점에 따라 Before Advice, After Advice 등으로 구현


[Pointcut]

여러 조인포인트의 집합으로 언제 어드바이스를 실행하는 위치 표시


[Aspect]

어드바이스(동작)와 포인트컷(동작을적용하는조건)을 조합해서 

횡단 관심사에 대한 코드와 그것을 적용할 지점을 정의한 것


Aspect :무엇을(Advice) 언제(Point) 할지 정의




2) 프로젝트 생성


 SpringAOP 프로젝트 만든다.


New>Spring Legacy Project>Simple Spring Utility Project(자바 콘솔에서 실행)


② Maven Repository에서 lib 다운


링크 : https://mvnrepository.com/


1) Spring AOP 

2) AspectJ Runtime 

3) AspectJ Weaver 

4) CGLib 

위의 4가지의 코드를 가져와 pom.xml에 붙여넣자.


-pom.xml

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
        <!-- spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        
        <!-- aspectjrt -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.10</version>
        </dependency>
        
        <!-- aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.10</version>
        </dependency>
        
        <!-- cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.4</version>
        </dependency>
cs


③ targetA, targetB 생성 및 작성


-targetA.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.exe.aop;
 
import org.springframework.stereotype.Component;
 
@Component("targetA")
public class TargetA {
 
    public void doSomething1() {
        //advice
        System.out.println("TargetA.doSomething1");
    }
    
    public void doSomething2() {
        System.out.println("TargetA.doSomething2");
    }
    
    public void doAnother1() {
        System.out.println("TargetA.doAnother1");
    }
    
    public void doAnother2() {    
        System.out.println("TargetA.doAnother2");
    }
}
cs


-targetB.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.exe.aop;
 
import org.springframework.stereotype.Component;
 
@Component("targetB")
public class TargetB {
 
    public void doSomething1() {
        //advice
        System.out.println("TargetB.doSomething1");
    }
    
    public void doSomething2() {
        System.out.println("TargetB.doSomething2");
    }
    
    public void doAnother1() {
        System.out.println("TargetB.doAnother1");
    }
    
    public void doAnother2() {
        System.out.println("TargetB.doAnother2");
    }    
}
cs


④ MyBeforeAdvice.java 생성 및 작성


1
2
3
4
5
6
7
8
package com.exe.aop;
 
public class MyBeforeAdvice {
    
    public void beforeMethodCall() {
        System.out.println("Jointpoint 메소드가 실행되기 전에...");
    }
}
cs


app-context.xml 작성


위의 코드 추가해준다.


app-context.xml에 위의 코드 써준다.

beforeAdvice라는 객체를 생성후 aspect의 매개변수로 넘겨준다.

beforePointcut이라는 이름을 임의로 정해서 포인트컷을 생성해주고

before의 기능을하는 aop:before에 매개변수로 생성한 포인트컷을 넘겨준다.

before는 beforeAdvice라는 객체의 메소드인 beforeMethodCall()이라는 함수를 메소드로 사용한다.


-app-context.xml

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
<?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" />
    
    <!-- 여기에 객체 생성 -->
    <!-- Advice -->
    <bean id="beforeAdvice" class="com.exe.aop.MyBeforeAdvice"/>
    
    <!-- Pointcut -->
    <!-- execution(public void com..aop.*.*(..)) -->
    <!-- execution(메소드접근지정자 반환값 패키지.클래스.메소드(매개변수)) -->
    <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>
cs


⑥ AopMain.java


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


-실행화면

⑦ after도 추가해보자


그 전 before는 주석처리하고 after만 실행해보자.


-MyAfterAdvice

1
2
3
4
5
6
7
8
package com.exe.aop;
 
public class MyAfterAdvice {
    
    public void afterMethodCall() {
        System.out.println("Jointpoint 메소드가 실행된 후에...");
    }
}
cs


-app-context.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    <!-- Pointcut -->
    <!-- execution(public void com..aop.*.*(..)) -->
    <!-- execution(메소드접근지정자 반환값 패키지.클래스.메소드(매개변수)) -->
    <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:config>
cs

aop:after로 형식에 맞취 써준다.


그리고 메인에서 실행


-실행화면


⑧ around 추가


-MyAroundAdvice.java

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
package com.exe.aop;
 
import org.aspectj.lang.ProceedingJoinPoint;
 
public class MyAroundAdvice {
 
    public Object aroundMethodCall(ProceedingJoinPoint jointPoint) {
        
        Object result=null;
        
        try {
            
            System.out.println("JointPoint 메소드 실행전..(Around)");
            
            result=jointPoint.proceed();//메소드 실행
            
            System.out.println("JointPoint 메소드 실행후..(Around)");
            
        } catch (Throwable e) {
            System.out.println(e.toString());
        }
        
        return result;
    }
}
cs


-app-context.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    <!-- Advice -->
    <bean id="aroundAdvice" class="com.exe.aop.MyAroundAdvice"/>
    
    <!-- Pointcut -->
    <!-- execution(public void com..aop.*.*(..)) -->
    <!-- execution(메소드접근지정자 반환값 패키지.클래스.메소드(매개변수)) -->
    <aop:config>
        
        <aop:aspect ref="aroundAdvice">
            <aop:pointcut id="aroundPointcut" expression="execution(public void com..aop.*.*Some*(..))"/>
            
            <aop:around method="aroundMethodCall" pointcut-ref="aroundPointcut"/>
        </aop:aspect>
        
    </aop:config>
cs

메소드의 형식을 *Some*으로 바꿔주었다.


-AopMain.java에서 똑같이 실행하면

-실행화면

*Some* 때문에 메소드의 이름에 Some이 들어가는 메소드에만 실행되는 모습을 볼 수 있다.


⑨ after-returning 추가


-MyAfterReturningAdvice.java

1
2
3
4
5
6
7
8
package com.exe.aop;
 
public class MyAfterReturningAdvice {
 
    public void afterReturningMethodCall() {
        System.out.println("JointPoint 메소드가 정상 실행한 뒤에..");
    }
}
cs


-app-context

1
2
3
4
5
6
7
8
9
    <bean id="afterReturningAdvice" class="com.exe.aop.MyAfterReturningAdvice"/>
    
    <aop:config>
        <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>
cs

메소드의 형식을 *A*1으로 바꾸고


-AopMain.java에서 똑같이 실행하면

-실행화면


⑩ after-throwing 추가

: 에러가 있을 때 실행됨


-MyAfterThrowingAdvice.java

1
2
3
4
5
6
7
8
9
package com.exe.aop;
 
//에러가 났을때
public class MyAfterThrowingAdvice {
 
    public void afterThrowingMethodCall() {
        System.out.println("JointPoint 메소드가 비정상 실행한 뒤에..");
    }
}
cs


-app-context.xml

1
2
3
4
5
6
7
8
9
10
11
12
    <bean id="afterThrowingAdvice" class="com.exe.aop.MyAfterThrowingAdvice"/>
    
    <!-- Pointcut -->
    <!-- execution(public void com..aop.*.*(..)) -->
    <!-- execution(메소드접근지정자 반환값 패키지.클래스.메소드(매개변수)) -->
    <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>
cs


-AopMain.java에서 똑같이 실행하면

-실행화면


-모두주석 풀고 패키지.클래스.메소드명 똑같이 맞춰준뒤 실행하면

아래처럼 전체메소드(Advice들)가 실행된다.




2. 전의 AOP코드를 Annotation으로 바꾸기 


app-context에 썻던코드들 다 주석처리하고 annotation으로 바꿔준다.


-MyBeforeAdvice.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.exe.aop;
 
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
 
@Aspect
@Component
public class MyBeforeAdvice {
    
    @Before("execution(* com..aop.*.*(..))")
    public void beforeMethodCall() {
        System.out.println("Jointpoint 메소드가 실행되기 전에...");
    }
}
cs


-app-context.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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>
cs

<aop:aspectj-autoproxy/>를 써주면 annotation을 쓸 수 있게 된다.


-나머지 파일도 before처럼 다 annotation써준뒤 메인에서 실행하면

아까 마지막처럼 전체 메소드들이 실행된다.

-실행화면




+ Recent posts