TIL(20240809) [spring 내부동작? 그리고 AOP와 트랜잭션 전파]
🔒 사용자가 API 요청에 대한 응답을 할 때 spring 내부 동작에 대해 설명해보자.
- springMVC패턴을 기반으로 말씀을 드리면
- 클라이언트가 HTTP요청을 서버로 보내면 이 요청을 spring의 내장 웹서버인 (Tomcat-was 등)에 의해 받게 되고 디스패처 서블릿이 이 요청을 처리하게 되는데,(handlermapping을 통해 해당 요청에 맞는 컨트롤러 정보를 받아온 후 handlerAdapter에게 전달하여) 해당 요청에 맞는 컨트롤러로 라우팅을 하게됩니다. 그리고 해당 요청이 매핑된 컨트롤러 메서드가 호출이 되고 이 메서드는 해당 비지니스 로직을 수행하는데, 필요한 경우에는 서비스 계층을 호출하여 데이터를 처리하게 됩니다. 여기서 데이터를 처리한다라고 하면은 데이터 조회나 외부 API호출 등을 의미하여 해당 작업을 수행함을 의미합니다. 그리고 컨트롤러는 처리결과를 기반으로 응답객체를 생성하는데,(handleradapter에게 전달하고 이를 받은 handleradapter는 model데이터와 view 이름을 반환) 이를 받은 디스패처 서블릿(viewresolver에게 view검색 요청하고 resolver는 view정보 반환, 다시 디스패처서블릿이 view에게 응답생성 요청하면 view는 응답생성 후 반환, thread에 응답을 담아서 반환)는 클라이언트에게 반환하게 됩니다.
인터셉터 : 디스패처 서블릿(Dispatcher Servlet)이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공
필터 : 디스패처 서블릿(Dispatcher Servlet)에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대해 부가작업을 처리할 수 있는 기능을 제공한다.
🔒 Spring AOP
- spring AOP는 핵심 비지니스 로직과 분리하여 모듈화하는 것을 의미하며 하는데요, 공통적으로 관심있는 기능을 구현할 때 사용하며 이 모듈화를 통해 코드의 재사용과 유지보수, 가독성을 향상할 수 있다고 알고 있습니다.
하나의 서버에는 여러개의 메서드가 있기 마련인데, 로그를 찍는다던가, 들어오는 매개변수와 리턴되는 결과를 보고 싶다던가, 메서드 실행 시간을 알고 싶은 경우에, 모든 메서드에 해당 기능들 코드를 작성하면 코드가 길어지고 가독성이 안 좋아질 뿐 아니라, 사람이 하다 보면 실수도 하기 마련입니다.
프록시객체의 개념
- 액세스 제어: 실제 객체를 사용할 수 있는 사람과 그 객체로 무엇을 할 수 있는지 결정합니다.
- 지연된 생성: 실제로 필요할 때까지 실제 객체를 생성하기를 기다립니다.
- 로깅: 실제 객체에 무슨 일이 일어나는지 추적합니다.
- 리소스 관리: 특히 복잡하거나 무거운 경우 실제 객체를 더 잘 처리하는 데 도움이 됩니다.
- 보안: 적합한 사람만 실제 물건을 사용할 수 있도록 보장합니다.
1) AOP의 단점
- AOP를 구현하기 위해 추가적인 의존성을 필요로 하며, 이는 프로젝트의 복잡성을 증가할 수 있고 스프링 AOP는 프록시 기반으로 작동하기 때문에 내부 메서드 호출시 프록시가 적용되지 않는 문제가 발생할 수 있습니다. 그래서 같은 클래스내에서는 AOP가 적용되지 않는 상황이 발생할 수 있다. 2) AOP 적용시 주의할 점
- AOP는 스프링 컨테이너에서 관리하는 빈만 적용되며 메서드 실행 시점에만 적용되기에 이러한 부분을 고려해서 AOP기능을 설계해야한다.
- 내부 호출문제 해결이 필요하다 (메서드 호출 구조 변경 내부에서 -> 외부로)
3) AOP 작동방식
프록시 생성: 스프링 AOP는 프록시 객체를 생성하여 부가 기능(Aspect)을 적용합니다. 이 프록시는 실제 객체를 대신하여 클라이언트의 요청을 처리하고, 부가 기능을 적용한 후 실제 객체의 메서드를 호출합니다. 외부 호출에 대한 프록시 적용: 프록시는 외부에서 객체의 메서드를 호출할 때만 작동합니다. 즉, 클라이언트가 프록시를 통해 메서드를 호출할 때 AOP가 적용됩니다. 내부 호출 문제: 같은 클래스 내에서 메서드가 호출될 경우, 이 호출은 프록시를 거치지 않고 직접 호출됩니다. 따라서 AOP의 부가 기능이 적용되지 않습니다. 이는 내부 메서드 호출이 프록시를 우회하기 때문입니다
- @Aspect AOP로 정의하는 클래스를 지정함
- @Pointcut AOP기능을 메소드, Annotation 등 어디에 적용시킬지 지점을 설정 지점을 설정하기 위한 수식들이 매우 많음
- @Before 메소드 실행하기 이전
- @After 메소드가 성공적으로 실행 후 (예외 발생 되더라도 실행 됨)
- @AfterReturning 메소드가 정상적으로 종료될때
- @AfterThrowing 메소드에서 예외가 발생할때
- @Around Before + After 모두 제어 (에외 발생 되더라도 실행 됨)
🔒 다양한 트랜잭션 전파 속성
- REQUIRED : 트랜잭션 기본 설정으로 기존 트랜잭션이 있으면 참여하고 트랜잭션이 없으면 새로운 트랜잭션을 생성합니다.
- SUPPORTS : 현재 트랜잭션을 실행하는데, 만약 아무런 트랜잭션이 없다면 트랜잭션 없이 실행합니다.
- MANDATORY : 트랜잭션이 의무이며 트랜잭션이 없다면 예외를 발생시킵니다.
- REQUIRES_NEW : 항상 새로운 트랜잭션을 생성하며 만약 트랜잭션이 존재한다면 현재 트랜잭션을 잠시 지연시킵니다.
- NOT_SUPPORTED : 현재 트랜잭션 실행하는데 만약에 트랜잭션이 없다면 트랜잭션 없이 실행합니다.
- NEVER : 트랜잭션을 사용하지 않으며 트랜잭션이 존재하면 예외를 발생시킵니다.
- NESTED : 기존에 트랜잭션이 있다면 중첩 트랜잭션을 만들고 기존 트랜잭션이 없다면 새로운 트랜잭션을 생성합니다. (중첩된 트랜잭션은 JPA 사용불가능) 현재 트랜잭션이 존재한다면 해당 트랜잭션을 이어서 실행합니다.
내부 롤백이 되더라도 외부에 영향을 주지 않기 위해서는 REQUIRES_NEW 정책을 사용해야 합니다. 외부와 내부 각각 별도의 트랜잭션이 생성되기 때문에 서로 독립적이므로 롤백이 영향을 주지 않습니다.(Suspending current transaction)
다른 정책의 트랜잭션 중첩은 트랜잭션 동기화 매니저에서 1개의 커넥션을 사용하지만, REQUIRES_NEW 정책의 경우 각각 커넥션을 생성하여 총 2개의 커넥션을 사용합니다. 커넥션을 2개나 사용한다는 점을 주의해야 합니다.
전파 속성에 따른 “롤백 유무”
중첩된 여러개의 트랜잭션이 롤백될 때 어떻게 동작하는지 이해하고 설계하는 것이 핵심입니다. NESTED는 내부의 예외가 외부까지 전파가 되지 않는데, 해당 기능은 JPA에는 적용이 되지 않는 단점이 있습니다.
- 필터와 인터셉터의 차이
- 서블릿이 무슨일을 하는가?
- uri와 getmapping, postmapping 관련된 것
- restcontroller , controller 응답객체 반환 과정은?
- Ioc의존성 역전: -> /DI: 의존성 주입 (service,repository)
- AOP @advice에 관해서 -before,after
- AOP에서 프록시객체를 어떻게 사용하는지(pointcut)
- 트랜잭션 전파전략 4개 required, mandatory, nested, requieres_new 어떤 상황에서 사용되는지, 어떻게 동작하는지 알고 있어야 함
- 롤백 체크드익셉션/언체크드익셉션(개발자 커스텀 가능)
- 트랜잭션 어떤 익셉션일때 롤백을 할건지 안할건지 트랜잭션 단위로 구분할 수 있는데 어떤것들이 있는지?
- 전파전략의 사전지식 -> 실제로 적용할 수 있는 방향
- 트랜잭션 isolation 공부까지 하는게 좋다.
카테고리해서 공부한 것들이 정리 (중요키워드)
- 스프링
- 자바
- 네트워크
- DB
- CS
- 자료구조 알고리즘
- 최종프로젝트 의사소통 문제 면접 답변 준비