[Spring Boot] 9. 리플렉션과 어노테이션 실습

김건우's avatar
Mar 25, 2025
[Spring Boot] 9. 리플렉션과 어노테이션 실습
package ex04; import java.io.File; import java.net.URL; public class App { public static void main(String[] args) { // 1. @Component가 붙으면 new해서 컬렉션에 담기 ClassLoader classLoader = ClassLoader.getSystemClassLoader(); URL packageUrl = classLoader.getResource("ex04"); File packageDir = new File(packageUrl.getFile()); for (File file : packageDir.listFiles()) { if (file.getName().endsWith(".class")) { String className = "ex04." + file.getName().replace(".class", ""); System.out.println(className); } } } }
notion image
package ex04; import java.io.File; import java.net.URL; import java.util.HashSet; import java.util.Set; public class App { public static void main(String[] args) { // 1. @Component가 붙으면 new해서 컬렉션에 담기 Set<Object> instances = new HashSet(); ClassLoader classLoader = ClassLoader.getSystemClassLoader(); URL packageUrl = classLoader.getResource("ex04"); File packageDir = new File(packageUrl.getFile()); for (File file : packageDir.listFiles()) { if (file.getName().endsWith(".class")) { String className = "ex04." + file.getName().replace(".class", ""); //System.out.println(className); try { Class cls = Class.forName(className); if (cls.isAnnotationPresent(Component.class)) { Object instance = cls.getDeclaredConstructor().newInstance(); instances.add(instance); } } catch (Exception e) { throw new RuntimeException(e); } } } // for 종료 for (Object instance : instances) { System.out.println(instance.getClass().getName()); } } }

1️⃣ Set<Object> instances = new HashSet();

  • instances는 @Component가 붙은 클래스들의 인스턴스를 저장하는 **컬렉션(Set)**입니다.
  • HashSet을 사용했기 때문에 중복이 허용되지 않습니다.

2️⃣ 패키지(ex04) 내부의 .class 파일을 탐색

ClassLoader classLoader = ClassLoader.getSystemClassLoader(); URL packageUrl = classLoader.getResource("ex04"); File packageDir = new File(packageUrl.getFile());
  • *ClassLoader*를 이용하여 ex04 패키지의 URL을 가져옵니다.
  • 이 URL을 이용해 File 객체로 변환하여 실제 파일 시스템에서 ex04 패키지의 클래스 파일들을 탐색할 준비를 합니다.

3️⃣ .class 파일 목록을 가져와 클래스 이름으로 변환

for (File file : packageDir.listFiles()) { if (file.getName().endsWith(".class")) { String className = "ex04." + file.getName().replace(".class", "
  • 패키지(ex04) 내부의 파일들을 가져와 .class 확장자로 끝나는 파일만 골라냅니다.
  • 파일명을 **클래스 이름(ex04.클래스명)**으로 변환하여 동적으로 클래스를 로드할 준비를 합니다.

4️⃣ 리플렉션을 사용하여 클래스 정보를 로드

Class cls = Class.forName(className);
  • Class.forName(className) → className을 이용해 **실제 클래스 객체(Class 타입)**를 가져옵니다.
  • 이렇게 하면 해당 클래스에 대한 정보를 동적으로 가져올 수 있습니다.

5️⃣ @Component가 붙어 있는지 확인

if (cls.isAnnotationPresent(Component.class)) {
  • cls.isAnnotationPresent(Component.class) → 해당 클래스에 @Component 어노테이션이 붙어 있는지 검사합니다. → true면 자동으로 인스턴스를 생성하고 instances에 추가합니다.

6️⃣ 객체를 생성하고 컬렉션(Set)에 저장

Object instance = cls.getDeclaredConstructor().newInstance(); instances.add(instance);
  • cls.getDeclaredConstructor().newInstance() → 클래스의 기본 생성자를 호출하여 객체를 동적으로 생성합니다. → 생성된 객체를 instances(Set)에 저장합니다.

7️⃣ @Component가 붙은 클래스들의 인스턴스 목록 출력

for (Object instance : instances) { System.out.println(instance.getClass().getName()); }
  • instances에 저장된 객체들의 클래스 이름을 출력합니다.
  • 즉, @Component가 붙은 클래스들의 이름이 콘솔에 출력됩니다.
package ex04; import java.io.File; import java.lang.reflect.Method; import java.net.URL; import java.util.HashSet; import java.util.Set; public class DispatcherServlet { public Set<Object> componentScan(String packageName) { // 1. @Component가 붙으면 new해서 컬렉션에 담기 Set<Object> instances = new HashSet(); ClassLoader classLoader = ClassLoader.getSystemClassLoader(); URL packageUrl = classLoader.getResource(packageName); File packageDir = new File(packageUrl.getFile()); for (File file : packageDir.listFiles()) { if (file.getName().endsWith(".class")) { String className = packageName + "." + file.getName().replace(".class", ""); //System.out.println(className); try { Class cls = Class.forName(className); if (cls.isAnnotationPresent(Component.class)) { Object instance = cls.getDeclaredConstructor().newInstance(); instances.add(instance); } } catch (Exception e) { throw new RuntimeException(e); } } } // for 종료 return instances; } public void routing(Set<Object> instances, String path) { for (Object instance : instances) { Method[] methods = instance.getClass().getMethods(); for (Method method : methods) { RequestMapping rm = method.getAnnotation(RequestMapping.class); if (rm == null) continue; // 다음 for문으로 바로 넘어감 if (rm.value().equals(path)) { try { method.invoke(instance); } catch (Exception e) { throw new RuntimeException(e); } } } } } }
package ex04; @Component public class BoardController { @RequestMapping("/write") public void write() { System.out.println("write call"); } @RequestMapping("/delete") public void delete() { System.out.println("delete call"); } }
package ex04; @Component public class UserController { @RequestMapping("/login") public void login() { System.out.println("login call"); } @RequestMapping("/join") public void join() { System.out.println("join call"); } @RequestMapping("/logout") public void logout() { System.out.println("logout call"); } @RequestMapping("/userinfo") public void userinfo() { System.out.println("userinfo call"); } }
package ex04; 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 Component { }
어노테이션
package ex04; 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.METHOD) // METHOD 메서드 위에만 붙힐 수 있다. (Class 위에 붙히려면 type을 적어야함) public @interface RequestMapping { String value(); }
어노테이션
notion image
Share article

gunwoo