4-4. MVC 시대 (실습 5)

박은서's avatar
Jan 29, 2026
4-4. MVC 시대 (실습 5)

실습 5. 컴포넌트 스캔(Component Scan)

[참고] 컴포넌트 스캔이란?

  • 패키지를 분석하는 기술
  • 패키지 경로를 기준으로 .class 파일을 찾고 리플렉션으로 클래스 메타데이터 분석
    • → 어노테이션(깃발) 달린 클래스 찾음
      → 객체를 생성하여 Spring 컨테이너가 관리하도록 등록
  • 목표 : RestController(어노테이션) 붙어 있는 클래스를 new 하는 것!
    • ※ 스캔 기준 : @Component 계열 전체 ⭕
      @RestController : @RestController =@Controller +@ResponseBody
      @Controller : @Controller@Component

1) RestController

package ex04.anno; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) // 런타임 시 실행 @Target(ElementType.TYPE) // 위치 : 클래스명 위 public @interface RestController { }

2) RequestMapping

package ex04.anno; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) // 동작 시점(컴파일 source? 실행시점 runtime?) @Target(ElementType.METHOD) // 위치 : 메서드 위 public @interface RequestMapping { String value(); // 어노테이션의 속성값(value라는 이름 사용 시에만 생략 가능) }

3) BoardController

package ex04; import ex04.anno.RequestMapping; import ex04.anno.RestController; @RestController public class BoardController { @RequestMapping("/insert") public void insert(){ System.out.println("insert 호출됨"); } @RequestMapping("/delete") public void delete(){ System.out.println("delete 호출됨"); } @RequestMapping("/update") public void update(){ System.out.println("update 호출됨"); } @RequestMapping("/select") public String select1(){ System.out.println("select 호출됨"); return "apple"; } }

4) UserController

user 정보를 관리하는 메서드가 있을 경우 해당 컨트롤러에서 메서드 관리
package ex04; public class UserController { }

5) App (main) (기초)

package ex04; import ex04.anno.RequestMapping; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; import java.util.Scanner; public class App { static void findUri(String uri) { // 3. 동적 클래스 분석 Method[] methods = BoardController.class.getDeclaredMethods(); for (Method m : methods) { RequestMapping rm = m.getDeclaredAnnotation(RequestMapping.class); if (rm.value().equals(uri)) { try { Object res = m.invoke(null); System.out.println("응답 버퍼 : " + res); } catch (Exception e) { e.printStackTrace(); // 피범벅 } } } } public static void main(String[] args) throws URISyntaxException { // 1. 키보드 입력 자리 String uri = "/insert"; // 2. 패키지 스캔 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // java 폴더 찾는 함수(문법) ref > out > production > classes 폴더 URL packageUrl = classLoader.getResource("ex04"); // java 폴더에 있는 'ex04' 찾는 것 (문법) File ex04Folder = new File(packageUrl.toURI()); // 폴더를 파일 객체로 받은 이유는 윈도우는 모든 것을 파일로 구분함 (문법) File[] files = ex04Folder.listFiles(); // 해당 폴더의 파일을 리스트에 담음(문법) anno, App, BoardController, UserController // 3. 찾은 것 검증 for (File f : files) { System.out.println(f.getName()); } } }

5-1) 결과

notion image

2) 찾은 것들 중 class 찾기

package ex04; import ex04.anno.RequestMapping; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; import java.util.Scanner; public class App { static void findUri(String uri) { // 3. 동적 클래스 분석 Method[] methods = BoardController.class.getDeclaredMethods(); for (Method m : methods) { RequestMapping rm = m.getDeclaredAnnotation(RequestMapping.class); if (rm.value().equals(uri)) { try { Object res = m.invoke(null); System.out.println("응답 버퍼 : " + res); } catch (Exception e) { e.printStackTrace(); // 피범벅 } } } } public static void main(String[] args) throws URISyntaxException, ClassNotFoundException { // 1. 키보드 입력 자리 String uri = "/insert"; // 2. 패키지 스캔 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // java 폴더 찾는 함수(문법) ref > out > production > classes 폴더 URL packageUrl = classLoader.getResource("ex04"); // java 폴더에 있는 'ex04' 찾는 것 (문법) File ex04Folder = new File(packageUrl.toURI()); // 폴더를 파일 객체로 받은 이유는 윈도우는 모든 것을 파일로 구분함 (문법) File[] files = ex04Folder.listFiles(); // 해당 폴더의 파일을 리스트에 담음(문법) anno, App, BoardController, UserController // 3. 찾은 것 검증 for (File f : files) { // System.out.println(f.getName()); if(f.getName().endsWith(".class")) { String className = "ex04."+f.getName().replace(".class", ""); // ex04.BoardController, ex04.UserController Class cls = Class.forName(className); // JVM이 문자열로 클래스 로딩하는 것 System.out.println(cls); } } } }
notion image

3) 어노테이션 달린 클래스 찾기

package ex04; import ex04.anno.RequestMapping; import ex04.anno.RestController; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; import java.util.Scanner; public class App { static void findUri(String uri) { // 3. 동적 클래스 분석 Method[] methods = BoardController.class.getDeclaredMethods(); for (Method m : methods) { RequestMapping rm = m.getDeclaredAnnotation(RequestMapping.class); if (rm.value().equals(uri)) { try { Object res = m.invoke(null); System.out.println("응답 버퍼 : " + res); } catch (Exception e) { e.printStackTrace(); // 피범벅 } } } } public static void main(String[] args) throws URISyntaxException, ClassNotFoundException { // 1. 키보드 입력 자리 String uri = "/insert"; // 2. 패키지 스캔 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // java 폴더 찾는 함수(문법) ref > out > production > classes 폴더 URL packageUrl = classLoader.getResource("ex04"); // java 폴더에 있는 'ex04' 찾는 것 (문법) File ex04Folder = new File(packageUrl.toURI()); // 폴더를 파일 객체로 받은 이유는 윈도우는 모든 것을 파일로 구분함 (문법) File[] files = ex04Folder.listFiles(); // 해당 폴더의 파일을 리스트에 담음(문법) anno, App, BoardController, UserController // 3. 찾은 것 검증 for (File f : files) { // System.out.println(f.getName()); if(f.getName().endsWith(".class")) { String className = "ex04."+f.getName().replace(".class", ""); // ex04.BoardController, ex04.UserController Class cls = Class.forName(className); // JVM이 문자열로 클래스 로딩하는 것 // System.out.println(cls); // 어노테이션 분석해서 담기 if (cls.isAnnotationPresent(RestController.class)) { System.out.println(cls); } } } } }
notion image

4) 찾은 것들을 new해서 컬렉션에 담기

package ex04; import ex04.anno.RestController; @RestController public class UserController { }
package ex04; import ex04.anno.RequestMapping; import ex04.anno.RestController; @RestController public class BoardController { @RequestMapping("/insert") public void insert(){ System.out.println("insert 호출됨"); } @RequestMapping("/delete") public void delete(){ System.out.println("delete 호출됨"); } @RequestMapping("/update") public void update(){ System.out.println("update 호출됨"); } @RequestMapping("/select") public String select1(){ System.out.println("select 호출됨"); return "apple"; } }
package ex04; import ex04.anno.RequestMapping; import ex04.anno.RestController; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class App { static void findUri(String uri) { // 3. 동적 클래스 분석 Method[] methods = BoardController.class.getDeclaredMethods(); for (Method m : methods) { RequestMapping rm = m.getDeclaredAnnotation(RequestMapping.class); if (rm.value().equals(uri)) { try { Object res = m.invoke(null); System.out.println("응답 버퍼 : " + res); } catch (Exception e) { e.printStackTrace(); // 피범벅 } } } } public static void main(String[] args) throws URISyntaxException, ClassNotFoundException, InstantiationException, IllegalAccessException { // 1. 키보드 입력 자리 String uri = "/insert"; // 2. 패키지 스캔 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // java 폴더 찾는 함수(문법) ref > out > production > classes 폴더 URL packageUrl = classLoader.getResource("ex04"); // java 폴더에 있는 'ex04' 찾는 것 (문법) File ex04Folder = new File(packageUrl.toURI()); // 폴더를 파일 객체로 받은 이유는 윈도우는 모든 것을 파일로 구분함 (문법) File[] files = ex04Folder.listFiles(); // 해당 폴더의 파일을 리스트에 담음(문법) anno, App, BoardController, UserController // 3. 찾은 것들을 new 해서 컬렉션에 담아두기 List<Object> iocContainer = new ArrayList<>(); // Inversion Of Controller (제어의 역전) for (File f : files) { // System.out.println(f.getName()); if(f.getName().endsWith(".class")) { String className = "ex04."+f.getName().replace(".class", ""); // ex04.BoardController, ex04.UserController Class cls = Class.forName(className); // JVM이 문자열로 클래스 로딩하는 것 // System.out.println(cls); // 어노테이션 분석해서 담기 if (cls.isAnnotationPresent(RestController.class)) { // System.out.println(cls); Object instance = cls.newInstance(); // 어떤 타입으로 new될 지 모르기 때문에 Object 타입 iocContainer.add(instance); } } } } }
notion image

5) 메서드 호출

package ex04; import ex04.anno.RequestMapping; import ex04.anno.RestController; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class App { static void findUri(String uri, Object obj) { // 3. 동적 클래스 분석 Method[] methods = obj.getClass().getDeclaredMethods(); for (Method m : methods) { RequestMapping rm = m.getDeclaredAnnotation(RequestMapping.class); if (rm.value().equals(uri)) { try { Object res = m.invoke(obj); System.out.println("응답 버퍼 : " + res); } catch (Exception e) { e.printStackTrace(); // 피범벅 } } } } public static void main(String[] args) throws URISyntaxException, ClassNotFoundException, InstantiationException, IllegalAccessException { // 1. 키보드 입력 자리 String uri = "/select"; // 2. 패키지 스캔 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // java 폴더 찾는 함수(문법) ref > out > production > classes 폴더 URL packageUrl = classLoader.getResource("ex04"); // java 폴더에 있는 'ex04' 찾는 것 (문법) File ex04Folder = new File(packageUrl.toURI()); // 폴더를 파일 객체로 받은 이유는 윈도우는 모든 것을 파일로 구분함 (문법) File[] files = ex04Folder.listFiles(); // 해당 폴더의 파일을 리스트에 담음(문법) anno, App, BoardController, UserController // 3. 찾은 것들을 new 해서 컬렉션에 담아두기 List<Object> iocContainer = new ArrayList<>(); // Inversion Of Controller (제어의 역전) for (File f : files) { // System.out.println(f.getName()); if(f.getName().endsWith(".class")) { String className = "ex04."+f.getName().replace(".class", ""); // ex04.BoardController, ex04.UserController Class cls = Class.forName(className); // JVM이 문자열로 클래스 로딩하는 것 // System.out.println(cls); // 어노테이션 분석해서 담기 if (cls.isAnnotationPresent(RestController.class)) { // System.out.println(cls); Object instance = cls.newInstance(); // 어떤 타입으로 new될 지 모르기 때문에 Object 타입 iocContainer.add(instance); } } } // 4. 메서드 호출 for (Object obj : iocContainer) { findUri(uri, obj); } } }
notion image
Share article