컴포넌트 스캔 / IoC

Jan 30, 2024
컴포넌트 스캔 / IoC

@RestController (컴포넌트 스캔) / IoC (제어의 역전)

notion image
일단... controller 패키지랑 HelloController 클래스를 만들어준다.
💡
DemoApplication 삭제하지 마라ㅠㅠ 스프링 부트를 실행하기 위해 필요한 핵심 클래스
 

1. 컴포넌트 스캔

@RestController 하면 컴포넌트 스캔이 됨 컴포넌트 스캔은 스프링이 지정된 패키지 또는 패키지의 하위에 있는 모든 클래스를 스캔하여 스프링이 직접 객체를 생성하고 관리할 수 있도록 하는 것 @RestController 어노테이션이 붙은 클래스들은 스프링이 해당 클래스의 인스턴스를 생성하고, 이를 스프링이 제공하는 IoC 컨테이너인 애플리케이션 컨텍스트에 등록한다 (= new를 해서 컬렉션 자료형에 담는다는 말) 애가 new되어서 메모리에 떠서 자료형에 담기는데, 그 자료형 이름을 IoC라고 함 컴포넌트 스캔의 기준점은 org.example.demo 이하에 있는 모든 클래스를 스캔 (다 찾는다)
💡
어려우면 그냥 @RestController가 붙은 애들을 스프링이 전부 다 new 한다. (=컴포넌트 스캔) 그 new 한 애를 자기가 만들어 놓은 컬렉션 자료형에 담는데, 그 자료형이 바로 IoC (인버전 오브 컨테이너)다. 라고 이해하자.

2. IoC (제어의 역전)

스프링 프레임워크에서는 제어의 역전(IoC) 컨테이너라는 개념을 도입하여, 객체의 생성과 관리를 스프링 프레임워크가 담당한다. 즉, new의 권한이 개발자한테 있는게 아니라 스프링 프레임워크에게 있다. 왜 ioc를 **제어의 역전**이라고 할까? 무슨 뜻일까? 원래 new를 개발자가 하잖아? 근데 지금은 new를 스프링이 하잖아? 스프링한테 new의 제어권을 빼앗겨서(위임해서) 제어의 역전이라고 함 왜 위임하냐? → 이건 이제부터 배울것. 위임했을때 뭐가 좋은지 아직은 안배워서 모른다
💡
스프링 : 내가 new 해줄테니까 개발자 너는 @만 붙이라고!!!
💡
IoC는 싱글톤이라 하나의 타입만 저장한다. (SET타입이라 동일한 타입을 넣어도 하나만 저장됨) HTTPServletRequest 객체는 IoC에 저장 못 한다. SET은 중복값을 저장하지 않으니까, Request가 100개가 와도 1개만 저장 되기 때문! 대신 세션은! IoC에 저장 가능!! 세션은 클라이언트와 서버 간의 상태를 유지하기 위한 객체로, 사용자의 세션 정보를 담고 있다. 세션은 요청마다 새로운 객체가 생성되는 것이 아니라, 클라이언트의 세션 ID에 해당하는 세션 객체를 찾아 사용하게 되기에 세션은 IoC 컨테이너에 저장되어 다른 객체에서 참조하고 활용할 수 있다.

3. @RestController이 붙은 클래스는 절대 가비지 컬렉션이 안된다

notion image
@RestController가 있으니 HelloController는 IoC 컨테이너에 new 되어서 저장된다 절대 가비지 컬렉션이 안된다. 스프링이 죽을 때까지 떠 있다. 즉, 싱글톤으로 딱 1개만 뜬다.
 

 
💡
스프링에서 어노테이션 종류가 엄청 많다.
스프링을 공부한다 = 어노테이션을 공부한다
 

실행 해 보기

notion image
스프링이 실행되면 컴포넌트 스캔을 통해 해당 패키지에 있는 클래스들을 스캔한다. (무조건 저 com.example.demo 패키지 아래에 있는 것만 스캔한다) 이때, @RestController 어노테이션이 붙은 클래스인 HelloController도 스캔 대상! 해당 클래스의 인스턴스를 생성하여 관리한다. (= 스프링에 의해서 new 되어있는 상태이니 home() 메소드를 바로 찾을 수 있음)
스프링은 메소드의 이름보다는 어노테이션을 기반으로 동작하므로, 메소드의 이름을 ohh() 이런걸로 변경해도 제대로 동작 함 (메소드의 이름은 중요하지 않다) 리플렉션(Reflection)을 통해 메소드를 호출하고 실행하기 때문!!
💡
home() 메소드는 어노테이션과 스프링의 리플렉션을 통해 작동하며, 메소드의 이름을 변경해도 여전히 동작
 

 
notion image
그래서 Application에서 실행하면...
notion image
notion image
new 된 것 확인! 생성될 때, 컴포넌트 스캔됐는지 알기 위해 초기화 시킨듯? 스프링이 new를 시켜줬으니까, (눈에는 보이지 않지만) 디폴트 생성자가 있을 것 아니야? 진짜 new가 된건지 알려고 생성자를 이용해서 출력한 것

전체 코드

package com.example.demo.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.Random; @RestController public class HelloController { //해당 컨트롤러 객체가 생성될 때 호출되는 초기화 코드. 기본생성자..가 쳐지겠지 public HelloController() { System.out.println("HelloController 컴포넌트 스캔됨"); } @GetMapping("/home") public void home() { System.out.println("home 호출 됨"); } @GetMapping("/hello") public String hello() { String name = "홍길동"; return "<h1>hello " + name + "</h1>"; } @GetMapping("/random") public String random() { Random r = new Random(); int num = r.nextInt(5)+1; return "<h1>hello " + num + "</h1>"; } }
 

[ 호출해보기 ]

notion image
notion image
내가 이렇게… 브라우저로 접속하자 [home 호출 됨] 하고 나옴 난 아무것도 한 게 없는데 통신이 되고 있네? 소켓이랑 다 .. 있는거네? 라는 걸 알 수 있다
 

오류 보기

notion image
notion image
Starting DemoApplication using Java 21.0.1 with PID 940 스프링부트 애플리케이션이 Java 21.0.1을 사용하고 PID 940으로 실행되었습니다 (스프링부트가 활성화 된 걸 알려줌) No active profile set -> 설정파일이 아직 없다. 이번에 실행할땐 이 포트써, 뭐 이런거... Tomcat initialized with port 8080 (http) 톰캣이 8080 포트를 사용하여 HTTP 프로토콜을 통해 웹 요청을 처리할 준비가 되었다 (일단은 이거 하나만 기억해놓자. (다 알아야하긴 함...))
 

사용자에게 응답해주고 싶다 (html코드랑 java 변수를 섞어서 응답)

사용자가 요청했을 때, [hello 홍길동]이라고 응답해주고 싶으면 return "<h1>hello " + name + "</h1>"; 를 사용한다.
notion image
notion image
지금 html코드랑 java 변수를 섞어서 응답했다 이 말은 html코드에 데이터 베이스 내용을 섞을 수 있다는 말! 데이터 베이스에서 조회된 변수를 자바 변수에 넣어서 html 코드랑 같이 응답할 수 있겠네!
💡
return 문은 스프링의 디스패처 서블릿에게 실행 결과를 반환하는 역할
 

[ 디스패처 오류 ]

notion image
이렇게 되면.. 디스패처(라우터)가 뭘 찾아야할지 몰라서 오류남
notion image
notion image
notion image
오류 메세지를 살펴보자. (오류가 나면 ㅠㅠ하지 말고 오류 코드를 봐라) 컴포넌트 스캔하면서 new를 못했다. 리퀘스트 매핑 오류가 났다 helloController() 메소드가 잘못됐다. 막 이렇게… 다 알려주네!! 에러 코드… 다 알려줘. 그러니까 읽어봐
💡
Bean == 객체
 

[ 요청할 때마다 변하는 페이지 만들기 ]

notion image
이렇게 만들어주면 (random 했잖아) 요청할 때마다 페이지가 변할 것이다.
notion image
notion image
요청할 때마다 달라지니까, 동적페이지 라고 함!!!
 

@RequestMapping 과 @GetMapping의 다른 점

@RequestMapping(value = "/random", method = RequestMethod.GET)
@GetMapping("/random") @PostMapping
@RequestMapping = 메서드 매개변수로 요청 메서드를 지정하여 사용 @GetMapping = HTTP GET 메서드에 대한 요청만 처리 (@RequestMapping의 축약형) 그럼 @PostMapping는 POST 메서드에 대한 요청만 처리하겠네
 

디스패처를 리플렉션으로 만들어준다는게 핵심

스프링 프레임워크 -> 디스패처를 리플렉션으로 만들어준다는게 핵심이다 (모든 객체들을 니가 new하지마. new는 내가 함. 넌 @해서 컨트롤러부터 만들어)
 

 
서블렛에 코드 다 때려 넣어도 되긴한데 (디스패처, 컨트롤러, dao 없어도 된단 말). 이게 없으면 다 각자 마구잡이로 하니까… 그걸 통일시킨게 스프링 프레임워크
Share article

codingb