TIL

day49 TIL

dalooong 2023. 7. 9. 14:05

23.06.27

미로 탐색 알고리즘

  • 게임맵최단거리
public class Maze {
    private int[] dx = new int[]{-1, 1, 0, 0};
    private int[] dy = new int[]{0, 0, 1, -1};

    public int solution(int[][] maze){
        // BFS 로직을 활용하는데
        // 다음에 접근할 수 있는 칸을 maze 의 가로 세로 크기 이내의
        // 칸을 기준으로 판단

        // int[]를 답는 Queue {x, y, 여태까지 이동거리}
        Queue<int[]> visitNext = new LinkedList<>();
        // 미로에서 이미 도달한 적 있는 칸임을 나타내기 위한 visited 이차원 배열
        boolean[][] visited = new boolean[6][6];
        visitNext.offer(new int[]{5, 0, 0});
        // BFS 시작
        int answer = -1;
        // Queue 가 비어있지 않은 동안
        while(!visitNext.isEmpty()) {
            // 다음에 갈 곳을 Queue 에서 꺼낸다.
            int[] next = visitNext.poll();
            int nowX = next[0];
            int nowY = next[1];
            int steps = next[2];

            if(maze[nowX][nowY] == 3) {
                answer = steps;
                break;
            }
            visited[nowX][nowY] = true;

            // 4방향을 확인한다.
            for (int dir = 0; dir < 4; dir++) {
                int nextX = nowX + dx[dir];
                int nextY = nowY + dy[dir];
                if(
                    // 1. 미로의 범위를 벗어나진 않는지
                        checkBounds(nextX, nextY) &&
                                // 2. 미로에서 진행 가능한 칸인지 ( 0 or 3)
                                (maze[nextX][nextY] == 0 || maze[nextX][nextY] == 3) &&
                                // 3. 아직 방문한적 없는지
                                !visited[nextX][nextY]
                ) {
                    visitNext.offer(new int[]{nextX, nextY, steps + 1});
                }
            }
        }

        return answer;
    }

    // 미로의 범위 내에 있는지 검사하는 메소드
    private boolean checkBounds(int x, int y) {
        return x > -1 && x < 6 && y > -1 && y < 6;
    }

    public static void main(String[] args) {
        System.out.println(new Maze().solution(new int[][]{
                {0, 0, 0, 0, 0, 3},
                {1, 0, 1, 1, 1, 0},
                {1, 0, 0, 0, 1, 0},
                {1, 0, 1, 0, 1, 0},
                {0, 0, 1, 0, 0, 0},
                {2, 1, 1, 0, 1, 1}
        }));
    }
}

AOP 관점 지향 프로그래밍 Aspect oriented programming

우리가 여태 개발한 것은 직접적인 비즈니스 로직에 해당한다.

여러 비즈니스 로직에 동일하게 작동하는 기능을 만들고 싶다면?

  • 메소드 실행의 걸린 시간
  • 메소드의 반환값 등

💡 횡단 관심 : 서로 다른 비즈니스 로직이 공통적으로 가졌으면 하는 기능

 

관점 지향 프로그래밍은 핵심 기능을 관리하는 코드는 건드리지 않으면서 여러 핵심 기능들이 활용할 수 있는 기능을 만드는데 초점을 맞추고 있다.

로깅과 같은 단순한 목적을 위해 소스 코드의 여러 부분에 흩어진 중복된 코드를 작성할 필요를 줄여준다.

 

@Transactional이란?

  • 한가지 일을 하는 일련의 코드들을 한 단위로 묶어서 작업을 처리하는 방법
  • 여러 작업을 진행하다가 문제가 생겼을 때 이전상태로 롤백하기 위해 사용되는 트랜잭션이다.

AOP 자주 사용하는 용어

  • Aspect: 횡단 관점에 적용할 기능을 모듈화한 단위. 즉, 어떤 핵심 기능에 추가할 횡단 기능에 대한 정의를 담는다.
  • Join Point : 실행 중이 프로그램에서 메소드 호출, 예외 발생 등의 시점을 지칭. 이러한 join point에 저희가 정의한 aspect를 적용할 수 있다.
  • Advice : 특정 join point에서 실제로 실행할 기능을 나타낸다. 이때 advice는 join point의 전before, 후after, 전후around 등 다양한 시점을 지칭할 수 있다.
  • Pointcut : 어느 특정한 join point를 지칭하기 위한 기준. advice가 실제로 적용될 join point를 정의하는 역할 ( 어떤 클래스의 메소드인지 등)
  • Weaving : 횡단 관점을 실제 프로그램에 적용시키는 과정

Aspect 정의하기

실습

  • 프로젝트 생성

  • aop는 자동 의존성이 없기 때문에 수동으로 의존성주입을 해주어야한다.
  • 아래 사이트에서 최신버전으로 선택해 가져와도 되지만, 뒤에 버전을 안붙이면 최신버전으로 설정이 자동적으로 된다.

Maven Repository: org.springframework.boot » spring-boot-starter-aop » 3.1.1

implementation 'org.springframework.boot:spring-boot-starter-aop:3.1.1'
implementation 'org.springframework.boot:spring-boot-starter-aop'

aop 실습

  • dto→ UserDto생성
@Data
public class UserDto {
    private Long id;
    private String username;
    private String password;
    private String passwordCheck;
    private String email;
    private String phone;
}
  • AopController 생성
@Slf4j
@RestController
@RequiredArgsConstructor
public class AopController {
    @PostMapping("/users")
    public ResponseDto addUser(@RequestBody UserDto user){
        log.info(user.toString());
        ResponseDto response = new ResponseDto();
        response.setMessage("addUser");
        return response;

    }
}
  • LoggingAspect 클래스 추가
@Slf4j  //log 추가
@Aspect //이클래스가 관점(Aspect)임을 드러내는 어노테이션
@Component //Bean 객체로 등록
public class LoggingAspect {
    //컨트롤러 클래스의 패키지를 포함한 full 명
    // @Before: Adivice: 실제로 실행될 코드를 나타냄
    // @Before.value: Pointcut Designator, 어느 joinpoint에서 실행될것인지
    @Before("this(com.example.aop.controller.AopController)")
    public void logParameters(JoinPoint joinPoint){
        log.info("hello aop!");
      
    }
}

postman

실행값

  • LoggingAspect수정
@Slf4j  //log 추가
@Aspect //이클래스가 관점(Aspect)임을 드러내는 어노테이션
@Component //Bean 객체로 등록
public class LoggingAspect {
    //컨트롤러 클래스의 패키지를 포함한 full 명
    // @Before: Adivice: 실제로 실행될 코드를 나타냄
    // @Before.value: Pointcut Designator, 어느 joinpoint에서 실행될것인지
    @Before("this(com.example.aop.controller.AopController)")
     //JoinPoint: 이 advice 가 실행된 joinpoint(adduser)
    public void logParameters(JoinPoint joinPoint){
        //signature : joinpoint의 정보를 담은 객체
        Signature signature = joinPoint.getSignature();
        //메소드 이름 로그
        log.info(signature.getName());
        //메소들 인자들 확인
        Object[] arguments = joinPoint.getArgs();
        //인자가 없을 때
        if (arguments.length == 0 ){
            log.info("no args");
        }
        for (Object argument : arguments)  {
            log.info("argument: [{}]", argument);
        }
    }
}

signature 코드 추가

적용해볼만한 Pointcut Designator

1. execution : 메소드 지정

 

execution : 메소드를 지정합니다. 이때, 클래스 내부의 메소드를 직접 지정할 수도 있지만, 클래스 내부의 메소드 전부를 지정하도록 할 수도 있습니다.

@Before("execution(public " +
    "com.example.aop.dto.ResponseDto " +
    "com.example.aop.AopController.addUser(" +
    "com.example.aop.dto.UserDto))")
// 또는
@Before("execution(public " +
    "com.example.aop.dto.ResponseDto " +
    "com.example.aop.AopController.*(..))")

2. withtin : 특정 클래스를 지정합니다. 클래스가 아니라 패키지 단위로 지정할수도 있습니다.

@Before("this(com.example.aop.AopController)")
// 또는
@Before("within(com.example.aop..*)")

3. @annotation : 어떤 특정 어노테이션이 붙은 Join Point를 지정합니다. 이 어노테이션은 저희가 직접 제작할 수 있습니다.

@Before("@annotation(com.example.aop.aspects.logging.LogArguments)")

 

AOP에서 Pointcut을 지정하는 방법은 다양하게 존재합니다. 상황에 맞는 Pointcut을 선택하도록 합시다.