코딩/sparta TIL

TIL 29 : 객체지향 설계, ApplicationContext, @ControllerAdvice VS @RestControllerAdvice

americanoallday 2025. 3. 28. 10:27

객제지향 설계


🥸 객체지향 설계를 하는 이유

코드가 점점 커지고 복잡해질 때 유지보수와 변경에 강한 “유연한 설계”를 하기 위해서

 

단일 책임 원칙(SRP, Single Responsibility Principle)

하나의 클래스는 하나의 책임만 가져야 한다.

🧐 Why?한 클래스가 여러 역할을 하면 수정할 때 연쇄적으로 망가질 가능성↑

🧠 비유

📦 택배기사 클래스가 “운전도 하고, 택배도 포장하고, 고객센터 전화까지 받는다?”

→ 운전 기능 하나 고치면 전화 기능이 깨짐 😱

 

개방 폐쇄 원칙(OCP, Open Closed Principle)

확장엔 열려 있고, 변경엔 닫혀 있어야 한다.

🧠 비유

🍕피자 가게가 “새 메뉴 추가할 때마다 요리사 클래스를 수정한다면?”

→ 요리사 터져버림 🧠💥

 

리스코프 치환 원칙(LSP, Liskov Substitution Principle)

부모 클래스 객체를 자식 클래스로 바꿔도 결과는 같아야 한다.

🧐 Why? 다형성을 믿고 썼는데, 자식이 부모보다 못하면 버그 발생 💣

 

인터페이스 분리 원칙(ISP, Interface Segregation Principle)

큰 인터페이스보다, 작은 인터페이스 여러 개가 낫다!

🧐 Why? 

→ 하나의 인터페이스가 너무 많은 기능을 강요하면,

→ 쓸모없는 메서드도 구현해야 함 💢

🧠 비유

학교선생님 인터페이스

teachMath(), teachEnglish(), teachScience()

→ 미술 선생님이 왜 과학을 가르쳐야 해…? 🤯

 

의존 관계 원칙(Dependency Inversion Principle)

상위 모듈(서비스)이 하위 모듈(구현)에 의존하면 안된다. (구현보다는 추상(인터페이스)에 의존해야함)

🧐 Why? 구체 클래스에 의존하면, 바뀔 때마다 다 수정해야 함


ApplicationContext

Spring Contatiner : Srping Bean 관리 기능

 

Spring Bean이란

더보기

✔ Spring에서 관리하는 객체(인스턴스)를 “Spring Bean”이라고 함.
    클래스 : 설계도 
    객체(Object) : 클래스로 만든 실체(인스턴스) → ⭐ 스프링 빈!

✔ 즉, Spring이 자동으로 생성하고, 관리하는 객체를 의미
    컨트롤러, 서비스, 레포지토리 같은 걸 만들 때, 클래스를 만들고 → 스프링이 객체를 만들어서 관리하게 함.

    그리고 그 **객체(=스프링 빈)**는 @Autowired, @Bean, @Service 등으로 다른 곳에 주입되거나 쓰이게 됨.

✔ Spring 컨테이너(Application Context)가 “Bean”을 생성하고, 필요할 때 주입(의존성 주입, DI)해 줌

 

Spring Bean 비유
📌 비유: “Spring은 큰 공장이고, Bean은 공장에서 만들어지는 제품”
✔ Spring 컨테이너 = 공장
✔ Spring Bean = 공장에서 만들어진 제품(객체)
✔ Spring 컨테이너가 모든 Bean을 생성하고, 관리함

 

BeanFactory : Spring Container의 "기본 기능"만 있는 인터페이스

ApplicationContext : BeanFactory를 확장한 "실무용 컨테이너" (BeanFactory를 상속한 자식 인터페이스)

 

🧊 BeanFactory (기본 기능만 있음)

 객체 생성 (빈 생성)

 의존성 주입 (DI)

 지연 로딩 (lazy loading)

 

☀️ ApplicationContext

✨ 국제화 (i18n) 지원 : 다국어 메시지 처리(영어/한글 번역 등)

✨ 이벤트 발행 기능 : ApplicationEventPublisher

✨ AOP 지원 : 프록시 기반 기능

✨ Bean 자동 등록, 스캔 지원 : @ComponentScan, @Configuration, @Autowired 

✨ Environment (설정 정보) 제공 : application.properties 읽기 등

✨ AnnotationConfigApplicationContext : 자바 기반 설정 지원

@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(MyApp.class, args);

        MyService service = context.getBean(MyService.class);
        service.doSomething();
    }
}

✔️ SpringApplication.run()이 반환하는 게 ApplicationContext

✔️ 그걸로 빈을 꺼낼 수도 있고, 설정 정보를 가져올 수도 있음.


서블릿 vs 스프링 빈 vs 컨트롤러(Spring Controller)

 서블릿은 요청을 처리하는 자바 클래스 (스프링 이전 방식)

 Spring은 직접 서블릿을 안 만들고, 대신 DispatcherServlet을 사용

 우리가 만드는 @Controller는 **스프링 빈(Spring Bean)**이고, 스프링 컨테이너가 관리함.

 → 결국, 서블릿 기반으로 동작하지만, 스프링이 다 알아서 해주니까 우리는 @Controller에만 집중하면 됨. 😄


@ControllerAdvice VS @RestControllerAdvice

공통점

전역적으로 모든 @Controller @RestController에서 발생하는 예외를 한 곳에서 처리해주는 역할.

@ExceptionHandler, @InitBinder, @ModelAttribute 등을 함께 사용 가능.

 

@ControllerAdvice

웹 MVC + 페이지 렌더링

 

@RestControllerAdvice 

@ControllerAdvice + ResponseBody, REST API 프로젝트 (JSON 응답)

➡️ "REST" 응답용이라 HTML, 이미지, 동영상 같은 뷰나 파일 응답은 처리하지 않음.

 

💡그럼 “웹페이지에서 이미지나 동영상 같은 건 어떻게 처리해요?”

➡️ “정적 리소스(static resources)“나 “파일 핸들링”으로 처리

 

🎨 예시로 보기: 이미지/동영상 처리

1️⃣ 정적 리소스 (static/images, static/videos 등)

src
└── main
    └── resources
        └── static
            ├── images
            │   └── cat.jpg
            └── videos
                └── intro.mp4

 

➡️ 그럼 클라이언트는 이렇게 요청 가능

GET http://localhost:8080/images/cat.jpg
GET http://localhost:8080/videos/intro.mp4

 

2️⃣ 사용자가 업로드한 파일

일반적으로 컨트롤러에서 이렇게 처리

@PostMapping("/upload")
public String handleFileUpload(@RequestParam MultipartFile file) {
    // 저장하고
    String savePath = "/upload/" + file.getOriginalFilename();
    file.transferTo(new File(savePath));
    return "업로드 완료!";
}

 

정리

역할 기능
REST API 오류 처리 @RestControllerAdvice
HTML 랜더링 / 뷰 페이지 @ControllerAdvice + 템플릿 (jsp, thymeleaf)
이미지, 동영상 static 폴더 + HTTP GET 처리
업로드/다운로드 파일 @RequestParam MultipartFile,
ResponseEntity<Resource>