---
title: "Java EE 정리 46"
date: "2019-05-02"
tags: ["Java EE","Spring"]
status: archived
verified: false
---

---

## Spring AOP

* **AOP(Aspect Oriented Programming, 관점지향 프로그래밍)**
* **종단 관심사 처리**
  * **== 상속, 부모에서 정의된 업무를 사용하기 싫어도 자식이 사용함**

![01](/md/legacy-assets/javaEe/46/01.webp)

* **횡단 관심사 처리**
  * **주기능에서 부기능을 분리할 수 있다**
    * **주 업무로직에서 부가적인 기능의 코드가 분리되어 코드의 복잡도가 낮아진다**
  * **상속과는 다르게 부가적인 기능이 필요한 코드에만 적용할 수 있다**
  * 아래 예와 같이 지문 찍는건 수업을 듣는 것과 아무런 관련이 없는 **부기능(횡단 관심사)**
  * **공통 로직을 중요하게 생각하는 설계에서는 AOP를 사용하는게 좋다**

![02](/md/legacy-assets/javaEe/46/02.webp)

## AOP 용어

![03](/md/legacy-assets/javaEe/46/03.webp)

## Advice가 동작하는 시점

![04](/md/legacy-assets/javaEe/46/04.webp)

## Spring AOP 설치

* **aspectjrt.jar, aspectjweaver.jar**가 필요
  * aspectjrt는 기본으로 Spring legacy에서 추가됨, weaver만 maven repository에서 다운 설치
* **pom.xml dependency 추가로 설치, WEB-INF/lib에 복붙으로 옮겨넣기**
  * [Maven Repository](https://mvnrepository.com/artifact/org.aspectj/aspectjweaver/1.9.3)

![05](/md/legacy-assets/javaEe/46/05.webp)

```html
<!-- pom.xml -->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.3</version>
</dependency>
```

* **설정파일에 AOP 사용 설정 추가**

```html
<aop:aspectj-autoproxy/>
```

![06](/md/legacy-assets/javaEe/46/06.webp)

* **Annotation 사용 설정, AOP 사용 설정**

```html
<!-- application-context.xml -->
...
      <context:annotation-config/>
      <context:component-scan base-package="kr.co.sist"/>
      <context:component-scan base-package="kr.co.sist.dao"/>
      <context:component-scan base-package="kr.co.sist.dao.*"/>
      <context:component-scan base-package="kr.co.sist.service"/>
      <context:component-scan base-package="kr.co.sist.service.*"/>
      
      <!-- AOP : 설정 후 annotation을 사용할 수 있음 -->
      <aop:aspectj-autoproxy/>
</beans>
```

## AOP Annotation - 클래스 위에 설정

* **@Aspect**
  * **Advice와 Pointcut의 합**

```java
@Aspect
class Test { ... }
```

## AOP Annotation - 메소드 위에 설정

* **method 위에 설정**
* **Advice가 동작하는 target method와 시점을 정의**
* **@Before**
  * **target method 호출 전에 Advice가 동작**

```java
@Before("execution(pointcut)")
public void someMethod() { ... }
```

* **@After**
  * **target method 호출 후 Advice가 동작**

```java
@After("execution(pointcut)")
public void someMethod() { ... }
```

* **@AfterReturning**
  * **target method 호출 후 return값이 반환된 후 Advice가 동작**

```java
@AfterReturning("execution(pointcut), return=리턴값")
public String someMethod() { ... } 
```

* **@AfterThrowing**
  * **target method에서 예외를 날린 후 Advice가 동작**

```java
@AfterThrowing("execution(pointcut)")
public String someMethod() throws SQLException { ... }
```

* **@Around**
  * **target method 전 후 Advice가 동작**

```java
@Around("execution(pointcut)")
public String someMethod() { ... }
```

* **target에 JoinPoint를 설정하는 표현식 Pointcut**
  * 적용 대상은 **method(target method)**
  
```java
@Before("execution(접근지정자 반환형 패키지명.클래스명.메소드명(매개변수타입))")
// 접근지정자 반환형 패키지명.클래스명 까지는 생략가능
@Before("execution(메소드명(매개변수타입))")

// ".."을 사용하면 모든 대상
// "*"을 사용할 수 있음(와일드 카드)
@Before(execution(public void kr.co.sist.controller.*Controller*.testMethod)
```

* **Advice 내에선 모든 객체를 받을 수 있다**
  * **JoinPoint**, **ProceedingJoinPoint** 두가지 사용하여 target에서 사용되는 parameter, return 값을 받을 수 있다
* **DI와 AOP를 사용한 예제**

![07](/md/legacy-assets/javaEe/46/07.webp)

```java
public class ItemDomain {
      
  private String itemNo, item;
  // getter, setter 생성
...
```

```java
public interface ItemDAO {
      
  public ItemDomain selectItem(String name) throws NumberFormatException;
}
```

```java
@Component
public class ItemDAOImpl implements ItemDAO {
  @Override
  public ItemDomain selectItem(String name) throws NumberFormatException {
    return new ItemDomain("IT_T01", name+"의 자신감있는 태도,  해박한 전문지식, 포장기술");
  }
}
```

```java
public interface ItemService {
      
  public ItemDomain searchItem(String name);
}
```

```java
@Component
public class ItemServiceImpl implements ItemService {
  @Autowired
  private ItemDAO i_dao;
  
  @Override
  public ItemDomain searchItem(String name) {
    
    ItemDomain id = i_dao.selectItem(name);
    System.out.println(id.getItemNo()+" / "+id.getItem());
    
    return id;
  }
}
```

```java
public class AopRun {
  
  public void execute() {
    ApplicationContext ac =
        new  ClassPathXmlApplicationContext("kr/co/sist/run/application-context.xml");
    
    ItemService is = ac.getBean(ItemService.class);
    ItemDomain id = is.searchItem("김희철");
  }
  
  public static void main(String[] args) {
    AopRun ar = new AopRun();
    ar.execute();
  }
}
```

![08](/md/legacy-assets/javaEe/46/08.webp)


* **이제 AOP를 적용시켜보자**
  * **target method 호출 전에 실행되는 advice**
  * **target method**는 String을 매개변수로 갖는 searchItem이란 이름의 method

```java
@Aspect
@Component
public class ItemAop {
      
      @Before("execution(* searchItem(String))")
      public void before() {
            System.out.println("before advice");
      }
}
```

![09](/md/legacy-assets/javaEe/46/09.webp)

* **target method 호출 후 실행되는 advice**

```java
@Aspect
@Component
public class ItemAop {
      
      @After("execution(* searchItem(String))")
      public void after() {
            System.out.println("after advice");
      }
}
```

![10](/md/legacy-assets/javaEe/46/10.webp)
