일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- bfs
- netlify
- 캡슐화
- Secret
- Java
- 동적계획법
- 메모이제이션
- DP
- CSS
- 다형성
- github
- dotenv
- Solid
- package
- 객체지향
- git
- PostgreSQL
- 클라우드
- 상속
- mock
- process.env
- 추상화
- 서브셋폰트
- 디자인 패턴
- GOF
- azure
- npm
- dfs
- AOP
- MariaDB
- Today
- Total
이것저것 해보기🌼
[AOP] 메소드 로그 찍기, Decode/Encode 하기 본문
AOP를 활용하여 메소드 실행 전,후, 타입, 값, 수행시간 등 다양한 로그를 남길수 있다.
먼저 Dependencies에 aop를 추가해주어야한다.
1
|
implementation 'org.springframework.boot:spring-boot-starter-aop'
|
cs |
예를 들어 아래와 같은 메소드 Controller가 정의되어있다고 하자.
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
|
package com.example.aop.controller;
import com.example.aop.annotation.Decode;
import com.example.aop.annotation.Timer;
import com.example.aop.dto.User;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class RestApiController {
@GetMapping("/get/{id}")
public String get(@PathVariable Long id, @RequestParam String name){
return id+" "+name;
}
@PostMapping("/post")
public User post(@RequestBody User user){
return user;
}
@Timer
@DeleteMapping("/delete")
public void delete() throws InterruptedException {
//db logic
Thread.sleep(1000*2);
}
@Decode
@PutMapping("/put")
public User put(@RequestBody User user){
System.out.println("put");
System.out.println(user);
return user;
}
}
|
cs |
1. 메소드 이름, 파라미터 타입, 값, 리턴값 확인
아래와 같이 AOP Annotation을 통해 메소드의 이름과 파라미터 타입, 값, 리턴값 등을 확인할 수 있다.
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 com.example.aop.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect //aop 사용
@Component //spring 으로 관리하겠다
public class ParameterAop {
@Pointcut("execution(* com.example.aop.controller..*.*(..))")
private void cut(){}
@Before("cut()") //cut() 메소드 실행 전에
public void before(JoinPoint joinPoint){
//method 이름 출력하기
MethodSignature methodSignature= (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
System.out.println(method.getName());
Object[] args = joinPoint.getArgs();
for(Object obj:args){
System.out.println("type:"+obj.getClass().getSimpleName());
System.out.println("value:"+obj);
}
}
//정상 실행 후 return 오브젝트 값 확인하고싶을때
@AfterReturning(value = "cut()", returning = "returnObj")
public void afterReturn(JoinPoint joinPoint, Object returnObj){
System.out.println("return obj:");
System.out.println(returnObj);
}
}
|
cs |
수행결과: localhost:8080/get/100?name=seohee GET 수행시,
get
type:Long
value:100
type:String
value:seohee
return obj:
100 seohee
2. 메소드 수행시간 확인
메소드의 수행시간을 재려면 아래와 같이 @Around를 사용한다.
- Timer Annotation 만들기
java class 만들기에서 Annotation 을 선택하여 Timer를 하나 생성한다.
1
2
3
4
5
6
7
8
9
10
11
|
package com.example.aop.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Timer {
}
|
cs |
그리고 아래와 같은 TimerAop 클래스를 하나 만든다.
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
|
package com.example.aop.aop;
//메소드 실행시간 등
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
@Aspect
@Component
public class TimerAop {
@Pointcut("execution(* com.example.aop.controller..*.*(..))")
private void cut(){}
@Pointcut("@annotation(com.example.aop.annotation.Timer)")
private void enableTimer(){}
@Around("cut() && enableTimer()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object result = joinPoint.proceed(); //method 실행
stopWatch.stop();
System.out.println("total time:"+stopWatch.getTotalTimeSeconds());
}
}
|
cs |
수행결과: delete 수행시,
delete
total time:2.0118792
3. Decode / Encode 수행 확인
다음은 decode / encode 방법이다.
예제는 이메일주소를 Base64 로 보낸 뒤, UTF-8로 디코드하여 내용을 출력하는 것이다.
마찬가지로 Decode 라는 annotation 을 생성한 후,
DecodeAop 클래스를 하나 작성한다.
이 클래스의 기능은 내가 원하는 arg인 User에 해당할경우 이메일주소를 디코드해서 객체에 저장하고,
값을 리터닝할때 다시 base64로 인코딩해서 리턴하는 것이다.
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
45
46
47
48
49
50
51
52
53
|
package com.example.aop.aop;
import com.example.aop.dto.User;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@Aspect
@Component
public class DecodeAop {
@Pointcut("execution(* com.example.aop.controller..*.*(..))")
private void cut(){}
@Pointcut("@annotation(com.example.aop.annotation.Decode)")
private void enableDecode(){}
@Before("cut() && enableDecode()")
public void before(JoinPoint joinPoint) throws UnsupportedEncodingException {
Object[] args = joinPoint.getArgs();
for(Object arg : args){
if(arg instanceof User){
User user = User.class.cast(arg);
String base64email = user.getEmail();
String email = new String(Base64.getDecoder().decode(base64email),"UTF-8");
user.setEmail(email); //user 객체 디코드
}
}
}
@AfterReturning(value = "cut() && enableDecode()", returning = "returnObj")
public void afterReturn(JoinPoint joinPoint, Object returnObj){
if(returnObj instanceof User ){
User user = User.class.cast(returnObj);
String email = user.getEmail();
String base64email = Base64.getEncoder().encodeToString(email.getBytes());
user.setEmail(base64email); //user 객체 디코드
}
}
}
|
cs |
그래서 main method를 이용해 먼저 원하는 이메일주소의 base64 인코딩 값을 확인해서, 이것을 PUT 메소드에 넣어 보냈다.
seohee@email.com 인코딩 :
c2VvaGVlQGVtYWlsLmNvbQ==
put 수행결과:
리턴값은 그대로 BASE64 코드로 돌아오는 것을 알수 있고,
이것을 decode & encode 하는 과정을 출력해보면 아래와 같았다.
'BE > Spring Boot' 카테고리의 다른 글
Validation, Exception 처리하기 (0) | 2021.07.05 |
---|---|
Annotation 정리 (0) | 2021.07.05 |
Spring 핵심 (0) | 2021.07.05 |
[Object Mapper] Object 를 text로 바꾸기 (0) | 2021.07.05 |
Response 내려주기 (0) | 2021.07.03 |