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

---

## Spring AOP 복습

* **핵심 로직에서 공통로직을 분리하기 위해 사용**
* **aspectjrt.jar, aspectjweaver.jar를 pom.xml에 정의**
* **설정파일에 AOP사용 설정**


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

* **AOP로 처리하는 공통로직**
  * **세션 존재 확인**
    * **메소드명을 ses를 붙이는 식으로 컨벤션을 정해서 모든 메소드에 적용시킬 수 있음**
  * **DB에서 커넥션 얻고 끊기 등**

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

* **어제 했던 예제를 변경해서 AOP를 사용해볼 것**

```java
public interface ItemService {
  public String getName(); // 추가된 abstract methods
  public String getAddr();
  public int getAge();
}
```

```java
@Component
public class ItemServiceImpl implements ItemService {
  @Autowired
  private ItemDAO i_dao;
  
  @Override
  public String getName() {
    String name = "김정윤";
    System.out.println("getName /// "+name);
    return name;
  }
  @Override
  public String getAddr() {
    String addr="서울시 강남구 역삼동";
    System.out.println("getAddr /// "+ addr);
    return addr;
  }
  @Override
  public int getAge() {
    int age = 30;
    System.out.println("getAge /// "+age);
    return age;
  }
}
```

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

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

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

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

* **패키지명을 명시하면 한정시켜서 target을 줄 수 있다**

```java
@Before("execution(* kr.co.sist.service.get*())")
```

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


* **Pointcut으로 target method를 한정할 수 있다**
  * **execution의 대상은 @Component가 붙어있는 Spring Bean**

```java
//     모든 Bean의 getter 호출
//     @Before("execution(* get*())") 
//     ItemServiceImpl의 getter 호출
//     @Before("execution(* kr.co.sist.service.ItemServiceImpl.get*())")
//     ItemServiceImpl의 반환형이 String인 getter 호출
       @Before("execution(String kr.co.sist.service.ItemServiceImpl.get*())") 
       public void getter() {
          System.out.println("getter before advice");
       }
```

## JoinPoint interface

* JoinPoint는 @Before, @After, @AfterReturning, @AfterThrowing에서 사용되는 **parameter를 Advice에서 처리하는 객체**
* **Advice의 매개변수로 정의**

```java
@Before(...)
public void test(JoinPoint jp) {
  Object[] objArr = jp.getArgs(); // target의 매개변수를 받아올 수 있다 
  
  Signature s = jp.getSignature();
  String methodName = s.getName(); // target method의 method명 얻기
  int modifier = s.getModifiers(); // target method의 접근지정자 얻기
}
```

* **JoinPoint 사용 예**

```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("이재찬");
    System.out.println(id.getItemNo());
    System.out.println(id.getItem());
  }
  
  public static void main(String[] args) {
    AopRun ar = new AopRun();
    ar.execute();
  }
}
```

* **org.aspectj.lang.Signiture 를 사용하면 method정보(매개변수, method명)을 얻을 수 있다**

```java
@Aspect
@Component
public class ItemAop {
  
  @Before("execution(* searchItem(String))")
  public void beforeItem(JoinPoint jp) {
        
    System.out.println("before advice");
    
    // target method의 매개변수 처리(JoinPoint를 사용하여)
    Object[] params = jp.getArgs();

    // target method의 method정보(매개변수, method명)
    Signature s = jp.getSignature();
    
    System.out.println("target method명 : "+s.getName());
    System.out.println("target method 접근지정자 : "+s.getModifiers());
    
    if (params != null) {
      System.out.println("매개변수 갯수 : "+params.length);
      
      for(Object param : params) {
        System.out.println("매개변수 값 : "+param);
      }
    }
  }
}
```

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

* **접근지정자는 숫자로 반환됨, java.lang.refelect.Modifier를 사용하면 문자열로 출력가능**

```java
System.out.println("target method 접근지정자 : "
    + (Modifier.isPublic(s.getModifiers()) ? "public" : "" ));
```

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

```java
System.out.println("target method 접근지정자 : "
    + Modifier.toString(s.getModifiers()));
```

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

## ProceedingJoinPoint interface

* **JoinPoint가 @Around에서만 사용**
* **target method parameter와 return value 처리하는 객체**
* **ProceedingJoinPoint사용 시 Advice 제작 주의점**
  * **advice method가 반드시 return을 가져야 함(void가 아니어야 함)**
    * Object도 괜찮고 아니면 target method의 반환형과 일치시켜도 됨
  * **매개변수에 ProceedingJoinPoint 선언**
  * **Advice method에 throws Throwable 정의**
  * **return value를 처리해야 한다**

```java
@Around( ... )
public 반환형 advice(ProceedingJoinPoint pjp) throws Throwable{
  Object o = pjp.proceed(); // target method의 반환값을 가져옴

  if (o instanceof String) { 
    // 반환값이 특정 클래스인지 확인할 때는 instanceof로 비교
  }

  return o;
}
```

* **ProceedingJoinPoint 사용 예**

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

```java
@Component
public class ItemServiceImpl implements ItemService {
...
  @Override
  public ItemDomain searchData(String name) {
        
    return new ItemDomain("IO_O001", name+" 애벌레, 크런커..");
  }
}
```

```java
@Aspect
@Component
public class ItemAop {
  
  @Around("execution(* searchData(..))") // ".."은 모든 매개변수
  public void around(ProceedingJoinPoint pjp) {
        
  }
...
```

```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.searchData("정택성");
    System.out.println(id.getItemNo());
    System.out.println(id.getItem());
  }
  
  public static void main(String[] args) {
    AopRun ar = new AopRun();
    ar.execute();
  }
}
```

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

```java
@Around("execution(* searchData(..))") // ".."은 모든 매개변수
public ItemDomain around(ProceedingJoinPoint pjp) throws Throwable {
  
// pjp.getArgs(); // target의 파라미터 처리가능
// pjp.getSignature(); // target method 정보사용

  // target의 리턴형을 받아와서 리턴을 만듦
  ItemDomain id = (ItemDomain)pjp.proceed(); // target method가 유일할 때
  if (id != null) {
      id.setItem(id.getItem()+"s('.^)V");
  }

  return id;
}

/*     @Around("execution(* searchData(..))") // ".."은 모든 매개변수
  public Object around(ProceedingJoinPoint pjp) throws Throwable {

    // target의 리턴형을 받아와서 리턴을 만듦
    Object o = pjp.proceed(); // target method가 여러개 일 때
    
    return o;
  }
*/     
```
