seaking110 님의 블로그
헷갈리는 개념 정리 본문
AOP vs Intercepter
- AOP
- 관점 지향형
- 횡단 관심사를 분리하여 모듈화하는 기법
- 즉 핵심 비즈니스 로직과 관계없는 공통 기능을 한 곳에서 관리할 수 있도록 기능
- 주요 기능
- Aspect : 공통적으로 적용할 기능
- Advice : 실행할 코드
- Pointcut : 적용할 대상 메서드 지정
- JoinPotin : 실행 가능한 모든 지점
- Weaving : 실제 코드에서 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.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Method 실행 전: " + joinPoint.getSignature().getName());
}
@AfterReturning("execution(* com.example.service.*.*(..))")
public void logAfterReturning(JoinPoint joinPoint) {
System.out.println("Method 실행 후: " + joinPoint.getSignature().getName());
}
}
- Interceptor (HandlerInterceptor)
- Spring MVC 에서 HTTP 요청을 가로채고 특정 로직을 실행하는 역할
- 즉 클라이언트가 컨트롤러에 도달하기 전에 실행되는 필터 역할
- 주요 기능
- preHanle() : 컨트롤러 실행 전에 실행
- postHandle () : 컨트롤러 실행 후에 실행
- afterCompletion(): View 렌더링 후 실행됨 (예외 발생 여부 상관없이 실행)
JWT 인증 인터셉터
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class JwtAuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String token = request.getHeader("Authorization");
if (token == null || !isValidToken(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
return true;
}
private boolean isValidToken(String token) {
// JWT 토큰 검증 로직 (단순 예제)
return token.startsWith("Bearer ");
}
}
비교 정리
비교 | AOP | Interceptor |
사용 목적 | 횡단 관심사 적용 (로깅 트랜잭션) | HTTP 요청 전후 처리 (인증 권한) |
적용 범위 | Spring Bean (서비스, 레파지토리) | Spring MVC 요청 처리 과정 |
실행 위치 | 메서드 실행 전후, 예외 발생 시 | 요청 전 후 / 응답 처리 |
주요 메서드 | @Before, @After, @Around | preHandle(), postHandle(), afterCompletion() |
주요 용도 | 로깅 트랜잭션, 성능 측정 | 인증, 권한 체크, 요청 로깅 |
등록 방식 | @Aspect + @Component | WebMvcConfigurer를 사용하여 addInterceptors()로 등록 |
적용 대상 | 모든 스프링 빈에서 사용 가능 | 컨트롤러 요청에 대해서만 동작 |
동기(Synchronous) vs 비동기 (Asynchronous)
DB와 연결되면 성능차이가 그렇게 크지 않다고 생각
- 동기란?
- 한 작업이 완료될 때까지 대기한 후 다음 작업을 수행하는 방식
- 순차적으로 실행되므로 코드의 실행 흐름을 예측하기 쉽지만 속도가 느림
- 특정 작업이 오래 걸릴 경우 다른 작업이 블로킹(Blocking) 됨
public class SyncExample {
public static void main(String[] args) {
System.out.println("작업 시작");
String result = fetchData(); // 데이터를 가져올 때까지 대기 (Blocking)
System.out.println("결과: " + result);
System.out.println("작업 종료");
}
public static String fetchData() {
try {
Thread.sleep(3000); // 3초 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
return "동기 처리 완료";
}
}
작업 시작
(3초 대기)
결과: 동기 처리 완료
작업 종료
- 비동기란?
- 한 작업을 실행하는 동안 다른 작업을 동시에 수행 가능 (즉 대기 X)
- 시간이오래 걸리는 작업을 비동기로 처리하면 성능이 향상
- Java에서는 @Async, CompletableFuture 등을 이용하여 비동기 진행
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Async // 별도 스레드에서 실행됨
public CompletableFuture<String> fetchDataAsync() {
try {
Thread.sleep(3000); // 3초 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
return CompletableFuture.completedFuture("비동기 처리 완료");
}
}
@RestController
@RequestMapping("/api")
public class AsyncController {
private final AsyncService asyncService;
public AsyncController(AsyncService asyncService) {
this.asyncService = asyncService;
}
@GetMapping("/async")
public CompletableFuture<String> getAsyncData() {
System.out.println("비동기 요청 시작"); //로거 그냥 안씀
CompletableFuture<String> future = asyncService.fetchDataAsync();
System.out.println("비동기 요청 종료");
return future;
}
}
비동기 요청 시작
비동기 요청 종료 <-- 3초 대기하지 않고 즉시 다음 코드 실행
(3초 후) 비동기 처리 완료
비교 정리
비교 항목
|
동기
|
비동기
|
작업 처리 방식
|
순차적으로 실행
|
동시에 여러 작업 가능
|
응답 대기 여부
|
요청이 끝날 때까지 대기
|
결과를 기다리지 않고 즉시 다음 코드 실행
|
성능
|
속도가 상대적으로 느림
|
대규모 트래픽에서 성능 향상
|
사용 방식
|
일반 메서드 호출
|
@Async, CompletableFuture, ExecutorService
|
적용 예제
|
CRUD, 데이터 조회
|
대량 데이터 처리, 비동기 API
|
Blocking vs Non-Blocking
- Blocking (블로킹)
- 작업을 수행할 때 결과가 나올 때까지 현재 스레드가 멈춰있는 방식
- 요청을 보낸 스레드는 결과를 받을 때 까지 아무 작업도 못하고 기다림
- 대표적인 예 : Java의 InputStream.read(), JDBC
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BlockingIOExample {
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
String line = reader.readLine(); // 파일 읽기 작업이 끝날 때까지 블로킹됨
System.out.println("읽은 데이터: " + line);
} catch (IOException e) {
e.printStackTrace();
}
}
}
(파일을 읽을 때까지 프로그램이 멈춰있음)
읽은 데이터: Hello World
- Non-Blocking
- 작업을 요청한 후 즉시 제어권을 반환하고 다른 작업을 수행할 수 있는 방식
- 요청을 보낸 스레드는 응답을 기다리지 않고 다른 작업 수행 가능
- Java NIO, WebFix 등
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;
public class NonBlockingIOExample {
public static void main(String[] args) {
System.out.println("파일 읽기 시작");
CompletableFuture.supplyAsync(() -> {
try {
return Files.readString(Path.of("data.txt"), StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}).thenAccept(content -> System.out.println("읽은 데이터: " + content));
System.out.println("다른 작업 수행 중...");
}
}
파일 읽기 시작
다른 작업 수행 중...
읽은 데이터: Hello World
차이점
비교 | Blocking | Non-Blocking |
작업 처리 방식 | 요청을 보낸 후 응답이 올때 까지 대기 | 요청을 보낸 후 즉시 다른 작업 수행 |
예제 | InputStream.read, JDBC | Java NIO,CompletableFuture |
스레드 효율 | 하나의 요청이 하나의 스레드를 점유 효율적이지는 않음 |
하나의 스레드가 여러 요청을 처리 효율적 |
적용 예시 | 일반적인 파일, I/O JDBC 연결 | WebFlux, Netty 기반 웹서버 |
장점 | 코드가 직관적이고 이해하기 쉽고 반드시 필요한 부분이 생김 | 성능 향상 |
단점 | 응답 대기 시간이 길어지면 성능 저하 | 코드가 복잡해 질 수 있음 |
- Sync vs Async 와 Blocking vs Non-Blocking는 다르다!!
- Blocking vs Non-Blocking은 "작업이 완료될 때까지 기다리는가?"의 차이
- Blocking → 스레드가 멈춰서 기다림
- Non-Blocking → 스레드가 기다리지 않고 다른 작업 수행 가능
- Sync vs Async는 "작업이 순차적으로 실행되는가?"의 차이
- Sync → 이전 작업이 끝나야 다음 작업 시작
- Async → 여러 작업을 동시에 진행 가능
동시성 VS 병렬성
- 동시성
- 하나의 CPU 코어에서 여러 작업을 번갈아가며 실행하는 방식
- 실제로 같은 순간에 여러 작업이 실행되는 것이 아닌 작업 간 전환(Context Switching)을 통해 빠르게 수행되는 것 처럼 보임
- 멀티 스레드, 비동기 프로그래밍과 관련
public class ConcurrencyExample {
public static void main(String[] args) {
Runnable task1 = () -> {
for (int i = 0; i < 5; i++) {
System.out.println("Task 1 실행 중...");
try { Thread.sleep(100); } catch (InterruptedException ignored) {}
}
};
Runnable task2 = () -> {
for (int i = 0; i < 5; i++) {
System.out.println("Task 2 실행 중...");
try { Thread.sleep(100); } catch (InterruptedException ignored) {}
}
};
new Thread(task1).start();
new Thread(task2).start();
}
}
번갈아가면서 실행됨
Task 1 실행 중...
Task 2 실행 중...
Task 1 실행 중...
Task 2 실행 중...
...
- 병렬성
- 여러 개의 CPU를 활용하여 여러 작업을 완전히 동시에 실행하는 방식
- 멀티코어 시스템에서 각 작업이 독립적으로 실행되며 속도가 크게 향상
- 멀티 프로세싱, 병령 스트림, ForkJoinPool과 관련됨
병렬성 예제 (자바 병렬 스트림)
import java.util.stream.IntStream;
public class ParallelExample {
public static void main(String[] args) {
IntStream.range(1, 10).parallel().forEach(i ->
System.out.println(Thread.currentThread().getName() + " - Task " + i)
);
}
}
ForkJoinPool.commonPool-worker-1 - Task 2
ForkJoinPool.commonPool-worker-2 - Task 3
ForkJoinPool.commonPool-worker-3 - Task 1
ForkJoinPool.commonPool-worker-1 - Task 4
...
- 여러 개의 CPU(멀티코어)를 사용하여 작업이 완전히 동시에 실행됨
- 동시성과 다르게 "스레드 전환"이 아니라 "각 작업이 독립적으로 실행됨"
차이점
비교 항목
|
동시성(Concurrency)
|
병렬성(Parallelism)
|
개념
|
여러 작업을 번갈아 실행 (스레드 전환)
|
여러 작업을 완전히 동시에 실행
|
CPU 개수
|
단일 CPU에서도 가능
|
멀티코어 CPU 필요
|
작업 방식
|
여러 작업을 빠르게 스위칭하여 처리
|
여러 작업을 동시에 실행
|
적용 기술
|
멀티스레딩, 비동기 처리
|
멀티프로세싱, 병렬 연산
|
장점
|
하나의 CPU로도 다중 작업 가능
|
성능 최적화, 대량 데이터 병렬 처리
|
단점
|
스레드 전환 오버헤드 발생
|
멀티코어 환경에서만 효과적, 비쌈
|
예제
|
웹 서버의 요청 처리, 비동기 이벤트 루프
|
머신러닝 연산, 대량 데이터 처리
|
동시성이 필요한 경우
웹 서버 요청 처리 (Spring MVC)
- HTTP 요청이 많을 때 멀티스레드를 사용하여 여러 요청을 동시 처리
- 하지만 각 요청이 같은 순간에 실행되는 것이 아니라 빠르게 전환되는 것
게임에서 여러 캐릭터의 행동 처리
- 한 캐릭터의 공격, 이동, 대화 이벤트가 동시에 발생하는 것처럼 보이지만 실제로는 번갈아가면서 실행됨
병렬성이 필요한 경우
머신러닝 모델 학습
- 각 CPU 코어에서 데이터를 병렬로 처리하여 속도를 크게 향상
비디오 렌더링
- 여러 개의 프레임을 여러 CPU에서 동시에 처리하여 성능 향상
Java의 ForkJoinPool (병렬 처리)
'Today I Learned' 카테고리의 다른 글
연관관계와 N+1 (0) | 2025.03.11 |
---|---|
테스트 코드 remind (1) | 2025.03.10 |
트러블 슈팅 (0) | 2025.02.27 |
프로젝트에 부족한 부분을 찾아 리팩토링 (0) | 2025.02.27 |
Cookie, JWT (0) | 2025.02.26 |