리플렉션(Reflection), 어노테이션(Annotation)

SHIN's avatar
Aug 18, 2024
리플렉션(Reflection), 어노테이션(Annotation)
 
notion image
 
  • Reflection → 속을 비추다 (코드 내부를 보는 것)
  • Annotation → JVM이 보는 주석 (힌트)
 

/스프링에서의 어노테이션 작동법/

 

1. Reflection 예제

  • Reflection 사용하지 않은 코드
 

1-1 UserController 생성

// 로그인, 회원가입, 유저정보 기능 제공 메소드 package ex01; public class UserController { public UserController() { } public void login() { System.out.println("login 호출됨"); } public void join() { System.out.println("join 호출됨"); } public void userinfo() { System.out.println("userinfo 호출됨"); } }
 

1-2 App class 생성

// 사용자가 입력한 URL에 따라 해당 메소드를 호출하도록 작성 package ex01; // A 개발자 public class app { public static void main(String[] args) { String path = "/userinfo"; UserController uc = new UserController(); if (path.equals("/login")) { uc.login(); } else if (path.equals("/join")) { uc.join(); } else if (path.equals("/userinfo")) { uc.userinfo(); } } }
 

1-3 컴파일

notion image
 
 
 
→ String path = “/userinfo”; 를 login으로 바꾸면,
notion image
 
💡
위 방식은 단순 path 변수를 통해 /login 또는 /userinfo 경로에 맞춰 UserController의 메소드를 호출. (확장성 떨어짐) → 새로운 메소드가 추가될 때 마다 App 클래스도 수정해야하기 때문.
 
 

2. Reflection 활용

* 리플렉션은 순서 보장 x
 
밑의 코드는 UserController 클래스의 메소드를 리플렉션을 통해 탐색하고 그 이름을 출력.
 

2-1 UserController 생성

package ex02; public class UserController { // /board/save-form @RequestMapping(uri = "/save-form") public void saveform() { System.out.println("saveform 호출됨"); } @RequestMapping(uri = "/userinfo") public void userinfo() { System.out.println("userinfo 호출됨"); } @RequestMapping(uri = "/login") public void login(){ System.out.println("login 호출됨"); } @RequestMapping(uri = "/join") public void join(){ System.out.println("join 호출됨"); } }
 

2-2 App class 생성

package ex02; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class App { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { String path = "/saveform"; UserController uc = new UserController(); // UserController란 클래스 안에 어떤 메소드들이 있는지 return Method[] methods = uc.getClass().getMethods(); for (Method mt : methods) { Annotation anno = mt.getDeclaredAnnotation(RequestMapping.class); RequestMapping rm = (RequestMapping) anno; if (rm == null) break; if (rm.uri().equals(path)) { mt.invoke(uc); } } } }
 
→ Method[ ] methods = uc.getClass().getDeclaredMethods(); 를 통해 UserController 안에 있는 메소드 이름 조회(실행) 가능.
 
 
  • 실행 코드
    • notion image
 
mt.invoke(uc); 를 사용하기 위해선 Exception이 필요함
→ 매개변수로 넣은 uc안에 메소드가 존재하지 않을 수 있기 때문
 
 

2-3 Annotation 정의

→ 어노테이션 사용 시 메소드 이름 대신 어노테이션 값 기준으로 동적 메소드 호출 가능.
 
  • RequestMapping 어노테이션 정의
package ex02; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) // 해당 깃발은 public @interface RequestMapping { String uri(); }
 
 

2-4 Annotation 적용

package ex02; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class App { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { String path = "/login"; UserController uc = new UserController(); // UserController란 클래스 안에 어떤 메소드들이 있는지 return Method[] methods = uc.getClass().getMethods(); for (Method mt : methods) { Annotation anno = mt.getDeclaredAnnotation(RequestMapping.class); RequestMapping rm = (RequestMapping) anno; if (rm == null) break; if (rm.uri().equals(path)) { mt.invoke(uc); } } } }
 
💡
어노테이션을 사용해 각 메소드가 어떤 URL 경로와 매핑되는지 정의 후, 런타임에 이 Mapping 정보를 바탕으로 메소드 호출. - path 변수만 변경하면 어떤 메소드든 호출 가능 - App 클래스 수정 필요x
 
 

 
 
Share article

SHIN