Java EE 정리 46
02 May 2019
Reading time ~2 minutes
Java EE 정리 46 - Spring AOP(1)
Spring AOP
- AOP(Aspect Oriented Programming, 관점지향 프로그래밍)
-
종단 관심사 처리
- == 상속, 부모에서 정의된 업무를 사용하기 싫어도 자식이 사용함
-
횡단 관심사 처리
-
주기능에서 부기능을 분리할 수 있다
- 주 업무로직에서 부가적인 기능의 코드가 분리되어 코드의 복잡도가 낮아진다
- 상속과는 다르게 부가적인 기능이 필요한 코드에만 적용할 수 있다
- 아래 예와 같이 지문 찍는건 수업을 듣는 것과 아무런 관련이 없는 부기능(횡단 관심사)
- 공통 로직을 중요하게 생각하는 설계에서는 AOP를 사용하는게 좋다
-
주기능에서 부기능을 분리할 수 있다
AOP 용어
Advice가 동작하는 시점
Spring AOP 설치
-
aspectjrt.jar, aspectjweaver.jar가 필요
- aspectjrt는 기본으로 Spring legacy에서 추가됨, weaver만 maven repository에서 다운 설치
- pom.xml dependency 추가로 설치, WEB-INF/lib에 복붙으로 옮겨넣기
<!-- pom.xml -->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.3</version>
</dependency>
- 설정파일에 AOP 사용 설정 추가
<aop:aspectj-autoproxy/>
- Annotation 사용 설정, AOP 사용 설정
<!-- 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의 합
@Aspect
class Test { ... }
AOP Annotation - 메소드 위에 설정
- method 위에 설정
- Advice가 동작하는 target method와 시점을 정의
-
@Before
- target method 호출 전에 Advice가 동작
@Before("execution(pointcut)")
public void someMethod() { ... }
-
@After
- target method 호출 후 Advice가 동작
@After("execution(pointcut)")
public void someMethod() { ... }
-
@AfterReturning
- target method 호출 후 return값이 반환된 후 Advice가 동작
@AfterReturning("execution(pointcut), return=리턴값")
public String someMethod() { ... }
-
@AfterThrowing
- target method에서 예외를 날린 후 Advice가 동작
@AfterThrowing("execution(pointcut)")
public String someMethod() throws SQLException { ... }
-
@Around
- target method 전 후 Advice가 동작
@Around("execution(pointcut)")
public String someMethod() { ... }
-
target에 JoinPoint를 설정하는 표현식 Pointcut
- 적용 대상은 method(target method)
@Before("execution(접근지정자 반환형 패키지명.클래스명.메소드명(매개변수타입))")
// 접근지정자 반환형 패키지명.클래스명 까지는 생략가능
@Before("execution(메소드명(매개변수타입))")
// ".."을 사용하면 모든 대상
// "*"을 사용할 수 있음(와일드 카드)
@Before(execution(public void kr.co.sist.controller.*Controller*.testMethod)
-
Advice 내에선 모든 객체를 받을 수 있다
- JoinPoint, ProceedingJoinPoint 두가지 사용하여 target에서 사용되는 parameter, return 값을 받을 수 있다
- DI와 AOP를 사용한 예제
public class ItemDomain {
private String itemNo, item;
// getter, setter 생성
...
public interface ItemDAO {
public ItemDomain selectItem(String name) throws NumberFormatException;
}
@Component
public class ItemDAOImpl implements ItemDAO {
@Override
public ItemDomain selectItem(String name) throws NumberFormatException {
return new ItemDomain("IT_T01", name+"의 자신감있는 태도, 해박한 전문지식, 포장기술");
}
}
public interface ItemService {
public ItemDomain searchItem(String name);
}
@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;
}
}
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();
}
}
-
이제 AOP를 적용시켜보자
- target method 호출 전에 실행되는 advice
- target method는 String을 매개변수로 갖는 searchItem이란 이름의 method
@Aspect
@Component
public class ItemAop {
@Before("execution(* searchItem(String))")
public void before() {
System.out.println("before advice");
}
}
- target method 호출 후 실행되는 advice
@Aspect
@Component
public class ItemAop {
@After("execution(* searchItem(String))")
public void after() {
System.out.println("after advice");
}
}