• Home
  • About
    • Young's Github Pages photo

      一日不作一日不食

    • About
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

Java EE 정리 47

03 May 2019

Reading time ~3 minutes

Java EE 정리 47 - Spring AOP(2)


Spring AOP 복습

  • 핵심 로직에서 공통로직을 분리하기 위해 사용
  • aspectjrt.jar, aspectjweaver.jar를 pom.xml에 정의
  • 설정파일에 AOP사용 설정
<aop:aspectj-autoproxy/>
  • AOP로 처리하는 공통로직
    • 세션 존재 확인
      • 메소드명을 ses를 붙이는 식으로 컨벤션을 정해서 모든 메소드에 적용시킬 수 있음
    • DB에서 커넥션 얻고 끊기 등

01

  • 어제 했던 예제를 변경해서 AOP를 사용해볼 것
public interface ItemService {
  public String getName(); // 추가된 abstract methods
  public String getAddr();
  public int getAge();
}
@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;
  }
}
@Aspect
@Component
public class ItemAop {
  
  @Before("execution(* get*())")
  public void getter() {
        System.out.println("getter before advice");
  }
}

02

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

  • 패키지명을 명시하면 한정시켜서 target을 줄 수 있다
@Before("execution(* kr.co.sist.service.get*())")

04

  • Pointcut으로 target method를 한정할 수 있다
    • execution의 대상은 @Component가 붙어있는 Spring Bean
//     모든 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의 매개변수로 정의
@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 사용 예
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명)을 얻을 수 있다
@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

  • 접근지정자는 숫자로 반환됨, java.lang.refelect.Modifier를 사용하면 문자열로 출력가능
System.out.println("target method 접근지정자 : "
    + (Modifier.isPublic(s.getModifiers()) ? "public" : "" ));

06

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

07

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를 처리해야 한다
@Around( ... )
public 반환형 advice(ProceedingJoinPoint pjp) throws Throwable{
  Object o = pjp.proceed(); // target method의 반환값을 가져옴

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

  return o;
}
  • ProceedingJoinPoint 사용 예
public interface ItemService {
       
  public ItemDomain searchItem(String name);
  public ItemDomain searchData(String name);
...
@Component
public class ItemServiceImpl implements ItemService {
...
  @Override
  public ItemDomain searchData(String name) {
        
    return new ItemDomain("IO_O001", name+" 애벌레, 크런커..");
  }
}
@Aspect
@Component
public class ItemAop {
  
  @Around("execution(* searchData(..))") // ".."은 모든 매개변수
  public void around(ProceedingJoinPoint pjp) {
        
  }
...
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

@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;
  }
*/     


Java EESpring