일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Dependency Injection
- 컨테이너
- Ubunt
- spring aop
- SpringJDBC
- Spring Boot
- Spring JDBC
- @test
- spring
- 프로퍼티
- JdbcTemplate
- 마이바티스
- 리눅스
- AOP
- @Spring-Test
- XML
- myBatis
- JDBC TEMPLATE
- @JUnit
- Di
- java
- spring framework
- POJO
- pointcut
- unix
- @AspectJ
- java spring
- Framework
- Linux
- STS
- Today
- Total
개키우는개발자 : )
AOP애플리케이션 작성(2) 본문
Spring Framework AOP애플리케이션 작성(2)
학습 목표
- Aspect 클래스 선언 및 설정
- Aspect 클래스 구현
- Aspect 클래스 테스트
1.Aspect 클래스 선언 및 설정
1-1 Spring AOP의 구현방식
XML 기반의 POJO 클래스를 이용한 AOP 구현
- 부가기능을 제공하는 Advice 클래스를 작성한다.
- XML 설정 파일에 <aop:config>를 이용해서 애스펙트를 설정한다.
(즉, 어드바이스와 포인트컷을 설정함)
@Aspect 어노테이션을 이용한 AOP 구현
- @Aspect 어노테이션을 이용해서 부가기능을 제공하는 Aspect 클래스를 작성한다. 이때 Aspect 클래스는 어드바이스를 구현하는 메서드와 포인트컷을 포함한다.
- XML 설정 파일에 <aop:aspectj-autoproxy />를 설정한다.
1-2 @Aspect 어노테이션
- Aspect 클래스 선언할 때 @Aspect 어노테이션을 사용한다.
- AspectJ 5버전에 새롭게 추가된 어노테이션이다.
- @Aspect 어노테이션을 이용할 경우 XML 설정 파일에 어드바이스와 포인트컷을 설정하는 것이 아니라 클래스 내부에 정의할 수 있다.
- <aop:aspectj-autoproxy> 태그를 설정파일에 추가하면 @Aspect 어노테이션이 적용된 Bean을 Aspect로 사용 가능하다.
1-3 Aspect 클래스 정보
- 클래스명 : LoggingAspect.java
- 클래스 기능 : 이 Aspect 클래스는 4가지 유형의 어드바이스와 포인트컷을 설정하여 타겟 객체의 파라미터와 리턴값, 예외 발생 시 예외 메시지를 출력하는 기능을 제공
- Advice 유형 : Before, AfterReturning, AfterThrowing, After
- 구현 메서드명 : before(JoinPoint joinPoint)
afterReturning(JoinPoint joinPoint , Object ret)
afterThrowing(JoinPoint joinPoint , Throwable ex)
afterFinally(JoinPoint joinPoint)
1-4 Aspect 클래스 선언 및 설정
- 클래스 선언부에 @Aspect 어노테이션을 정의한다.
- 이 클래스를 애스펙트로 사용하려면 Bean으로 등록해야 하므로 @Component 어노테이션도 함께 정의한다.
- XML 설정파일에 <aop:aspectj-autoproxy /> 선언한다. 이 선언은 Bean으로 등록된 클래스 중에서
@Aspect가 선언된 클래스를 모두 애스펙트로 자동 등록 해주는 역할을 한다.
New -> package -> myspring.aop.annot 패키지 생성
myspring.aop.annot 패키지 하위 -> New -> class -> LoggingAspect 클래스 파일 생성
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 33 34 35 36 37 38 39 40 41 42 43 44 | package myspring.aop.annot; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component @Aspect public class LoggingAspect { @Before("execution(public * myspring..*(..))") public void before(JoinPoint joinPoint) { String signatureString = joinPoint.getSignature().getName(); System.out.println("@Before [" + signatureString + "] 메서드 실행 전처리 수행"); for(Object arg:joinPoint.getArgs()) { System.out.println("@Before [" + signatureString + "] 아규먼트" + arg); } } @AfterReturning(pointcut="execution(public * myspring.user.service.*.*(..))",returning="ret") public void afterReturning(JoinPoint joinPoint, Object ret) { String signatureString = joinPoint.getSignature().getName(); System.out.println("@AfterReturning [" + signatureString + "] 메서드 실행 후처리 수행"); System.out.println("@AfterReturning [" + signatureString + "] 리턴값 = "+ret); } @AfterThrowing(pointcut="execution(* *..UserService*.*(..))",throwing="ex") public void afterThrowing(JoinPoint joinPoint, Throwable ex) { String signatureString = joinPoint.getSignature().getName(); System.out.println("@AfterThrowing [" + signatureString + "] 메서드 실행 중 예외 발생"); System.out.println("@AfterThrowing [" + signatureString + "] 예외 = "+ex); } @After("execution(* *..*.*User(..))") public void afterFinally(JoinPoint joinPoint) { String signatureString = joinPoint.getSignature().getName(); System.out.println("@After [" + signatureString + "] 메서드 실행 완료"); } } | cs |
New -> spring -> Spring Bean Configuration File -> annot.xml 생성
New -> spring 검색
annot.xml 생성
xml namespace 설정
1 2 3 4 5 6 7 8 9 10 11 | <?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <!-- 어노테이션이 선언된 클래스들을 스캔하기 위한 설정 --> <context:component-scan base-package="myspring.di.annot" /> </beans> | cs |
2.Aspect 클래스 구현
2-1 Advice를 정의하는 어노테이션
- Advice를 정의하기 위하여 아래와 같은 어노테이션을 제공한다.
- @Before("pointcut")
- 타겟 객체의 메서드가 실행되기 전에 호출되는 어드바이스
- JoinPoint를 통해 파라미터 정보를 참조할 수 있다.
- @After("pointcut")
- 타겟 객체의 메서드가 정상 종료 됐을 때와 예외가 발생했을 때 모두 호출되는 어드바이스
- 리턴값이나 예외를 직접 전달받을 수는 없다.
- @Around("pointcut")
- 타겟객체의 메서드가 호출되는 전 과정을 모두 담을 수 있는 가장 강력한 기능을 가진 어드바이스
- @AfterReturning(pointcut="",returning="")
- 타겟 객체의 메서드가 정상적으로 실행을 마친 후에 호출되는 어드바이스
- 리턴값을 참조할 때는 returning 속성에 리턴값을 저장할 변수 이름을 지정해야 한다.
- @AfterThrowing(pointcut="",throwing="")
- 타겟 객체의 메서드가 예외가 발생하면 호출되는 어드바이스
- 발생된 예외를 참조할 때는 throwing 속성에 발생한 예외를 저장할 변수 이름을 지정해야 한다.
1 2 3 4 5 6 7 8 | @Before("execution(public * myspring..*(..))") public void before(JoinPoint joinPoint) { String signatureString = joinPoint.getSignature().getName(); System.out.println("@Before [" + signatureString + "] 메서드 실행 전처리 수행"); for(Object arg:joinPoint.getArgs()) { System.out.println("@Before [" + signatureString + "] 아규먼트" + arg); } } | cs |
2-3 AfterReturning 어드바이스
- @AfterReturning 어드바이스를 이용해서 실행되는 타겟 객체의 메서드명과 리턴값을 출력하는 어드바이스이다.
- 아래의 afterReturning 메서드는 myspring.user.service 패키지 하위에 있는 모든 public 메서드가 정상 종료된 이후에 호출된다.
- 리턴값을 참조할 때는 returning 속성을 이용해서 리턴 값을 담을 변수 이름을 지정해야 한다.
1 2 3 4 5 6 | @AfterReturning(pointcut="execution(public * myspring.user.service.*.*(..))",returning="ret") public void afterReturning(JoinPoint joinPoint, Object ret) { String signatureString = joinPoint.getSignature().getName(); System.out.println("@AfterReturning [" + signatureString + "] 메서드 실행 후처리 수행"); System.out.println("@AfterReturning [" + signatureString + "] 리턴값 = "+ret); } | cs |
2-4 AfterThrowing 어드바이스
- @AfterThrowing 어드바이스를 이용해서 실행되는 타겟 객체의 메서드명과 예외 메시지를 출력하는 어드바이스이다.
- 아래의 afterThrowing 메서드는 클래스명이 UserService로 시작되는 클래스에 속한 모든 메서드가 예외가 발생된 이후에 호출된다.
- 발생된 예외를 참조할 때는 throwing 속성을 이용해서 예외 객체를 담을 변수 이름을 지정해야 한다.
1 2 3 4 5 6 | @AfterThrowing(pointcut="execution(* *..UserService*.*(..))",throwing="ex") public void afterThrowing(JoinPoint joinPoint, Throwable ex) { String signatureString = joinPoint.getSignature().getName(); System.out.println("@AfterThrowing [" + signatureString + "] 메서드 실행 중 예외 발생"); System.out.println("@AfterThrowing [" + signatureString + "] 예외 = "+ex); } | cs |
2-5 After 어드바이스
- @After 어드바이스를 이용해서 실행되는 타겟 객체의 메서드명을 출력하는 어드바이스이다.
- 아래의 afterFinally 메서드는 메서드명이 User로 끝나는 메서드들이 정상 종료됐을 때와 예외가 발생했을 때 모두 호출된다.
- 반드시 반환해야 하는 리소스가 있거나 메서드 실행 결과를 항상 로그로 남겨야 하는 경우에 사용할 수 있다.
하지만 리턴 값 이나 예외를 직접 전달받을 수는 없다.
1 2 3 4 5 | @After("execution(* *..*.*User(..))") public void afterFinally(JoinPoint joinPoint) { String signatureString = joinPoint.getSignature().getName(); System.out.println("@After [" + signatureString + "] 메서드 실행 완료"); } | cs |
3.Aspect 클래스 테스트
3-1 Aspect 클래스 테스트(정상)
- UserService Bean의 getUser 메서드를 호출하면, Advice가 적용된 것을 확인해 볼 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | UserService.getUser(..)시작 ///////////////////advice 시작////////////////////// @Before [getUser] 메서드 실행 전처리 수행 @Before [getUser] 아규먼트user1 @Before [read] 메서드 실행 전처리 수행 @Before [read] 아규먼트user1 @After [getUser] 메서드 실행 완료 @AfterReturning [getUser] 메서드 실행 후처리 수행 @AfterReturning [getUser] 리턴값 = {"userid":"user1","name":"name1","gender":"여","city":"city1"} ///////////////////advice 종료////////////////////// UserService.getUser(..)종료 UserService.getUser(..)실행 시간 : 242 ms {"userid":"user1","name":"name1","gender":"여","city":"city1"} | cs |
3-2 Aspect 클래스 테스트(예외발생)
- UserService Bean의 getUser 메서드가 예외 발생 시, Advice가 적용된 것을 확인해 볼 수 있다.
1 2 3 4 5 6 7 | UserService.updateUser(..)시작 @Before [updateUser] 메서드 실행 전처리 수행 @After [updateUser] 메서드 실행 완료 @AfterThrowing [updateUser] 메서드 실행 중 예외 발생 @AfterThrowing [updateUser] 예외 = java.lang.StackOverflowError UserService.updateUser(..)종료 UserService.updateUser(..)실행 시간 : 3 ms | cs |
3-3 Aspect 클래스 테스트(회원수정)
1 2 3 4 5 6 7 8 | @Test public void updateUserTest() { service.updateUser(new UserVO("user1","name4","남","city4")); for(UserVO user:service.getUserList()) { System.out.println(user); } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | UserService.updateUser(..)시작 @Before [updateUser] 메서드 실행 전처리 수행 @Before [updateUser] 아규먼트{"userid":"user1","name":"name4","gender":"남","city":"city4"} @Before [update] 메서드 실행 전처리 수행 @Before [update] 아규먼트{"userid":"user1","name":"name4","gender":"남","city":"city4"} 수정된 UserId = user1 @After [updateUser] 메서드 실행 완료 @AfterReturning [updateUser] 메서드 실행 후처리 수행 @AfterReturning [updateUser] 리턴값 = 1 UserService.updateUser(..)종료 UserService.updateUser(..)실행 시간 : 72 ms UserService.getUserList()시작 @Before [getUserList] 메서드 실행 전처리 수행 @Before [readAll] 메서드 실행 전처리 수행 @AfterReturning [getUserList] 메서드 실행 후처리 수행 @AfterReturning [getUserList] 리턴값 = [{"userid":"user1","name":"name4","gender":"남","city":"city4"}, {"userid":"user2","name":"name2","gender":"여","city":"서울"}, {"userid":"user3","name":"name3","gender":"여","city":"city3"}, {"userid":"ㄴㄴㄴ","name":"ㄴㄴㄴ","gender":"남","city":"서울"}] UserService.getUserList()종료 UserService.getUserList()실행 시간 : 8 ms {"userid":"user1","name":"name4","gender":"남","city":"city4"} {"userid":"user2","name":"name2","gender":"여","city":"서울"} {"userid":"user3","name":"name3","gender":"여","city":"city3"} {"userid":"ㄴㄴㄴ","name":"ㄴㄴㄴ","gender":"남","city":"서울"} | cs |
완성된 프로젝트 코드를 다운받으실수 있습니다.
'JAVA > Spring Framework' 카테고리의 다른 글
MyBatis(마이바티스) 애플리케이션 작성(1) (0) | 2019.02.09 |
---|---|
MyBatis(마이바티스) 개요 (2) | 2019.02.08 |
AOP애플리케이션 작성(1) (0) | 2019.02.08 |
AOP 개요 (0) | 2019.02.08 |
Spring Framework JDBC 환경설정 (0) | 2019.02.07 |