[스프링부트, 기술정리]리플렉션(Reflection), 어노테이션(Annotations)

송송승현's avatar
Nov 20, 2024
[스프링부트, 기술정리]리플렉션(Reflection), 어노테이션(Annotations)

리플렉션(Reflection)

💡
JAVA에서 클래스, 메서드, 변수 등의 구조를 런타임에 동적으로 검사하고 조작할 수 있는 기능
이를 통해 객체의 메타데이터에 접근하고, 동적으로 메서드를 호출하거나 필드 값을 변경할 수 있다.

어노테이션(Annotations)

💡
코드에 메타데이터를 추가하는 방법으로, 주석과 달리 런타임에 사용할 수 있다.
코드의 가독성을 높이고, 컴파일러나 런타임 환경에서 특정 동작을 수행
 

적용 전 예제 코드

/** * 1차 개발자가 작성하는 코드 */ public class Router { UserController uc; public Router(UserController uc){ this.uc = uc; } public void routing(String path){ if(path.equals("/login")){ uc.login(); }else if(path.equals("/join")){ uc.join(); } } } /** * 2차 개발자가 작성하는 코드 * 한계 : logout이라는 메소드가 필요한 상황 - 1차 개발자가 작성한 Router를 * 건드리지 못함, 1차 개발자한테 해달라해야함 */ public class UserController { public void login(){ System.out.println("로그인"); } public void join(){ System.out.println("회원가입"); } public void logout(){ System.out.println("로그아웃"); } } public class App { public static void main(String[] args) { Router router = new Router(new UserController()); Scanner sc = new Scanner(System.in); String path = sc.nextLine(); router.routing(path); } }
 

적용 후 예제코드

@Retention(RetentionPolicy.RUNTIME) // 언제 실행할건지 @Target(ElementType.METHOD) // 어디에 붙이는지 public @interface RequestMapping { String value(); } /** * 1차 개발자가 작성하는 코드 */ public class Router { UserController uc; public Router(UserController uc){ this.uc = uc; } public void routing(String path){ // 1. 메서드 찾아내기 Method[] methods = uc.getClass().getMethods(); // 2. 어노테이션 체크하기 for(Method m : methods){ if(m.isAnnotationPresent(RequestMapping.class)){ RequestMapping rm = m.getAnnotation(RequestMapping.class); // 3. value와 path 일치 확인해서 일치하면 invoke 하기 if(rm.value().equals(path)){ try { m.invoke(uc); } catch (Exception e) { throw new RuntimeException("메서드 실행중 오류가 발생했어요."); } } } } } } /** * 2차 개발자가 작성하는 코드 * 어노테이션을 만들어놓음으로 UserController에 다른 메서드들을 생성해도 사용 할 수 있는 * 코드 생성 */ public class UserController { @RequestMapping(value = "/login") public void login(){ System.out.println("로그인"); } @RequestMapping("/join") public void join(){ System.out.println("회원가입"); } @RequestMapping("/logout") public void logout(){ System.out.println("로그아웃"); } @RequestMapping("/userinfo") public void userInfo(){ System.out.println("유저 정보"); } } public class App { public static void main(String[] args) { Router router = new Router(new UserController()); Scanner sc = new Scanner(System.in); String path = sc.nextLine(); router.routing(path); } }

장점

리플렉션(Reflection)

  • 동적 동작 : 컴파일 시점에 알 수 없는 클래스, 메서드, 필드 등을 런타임에 동적으로 탐색하고 사용
  • 확장성 : 플러그인 기반 아키텍처나 프레임워크에서 유연한 설계 가능
  • 검증 및 디버깅 : 런타임에 객체의 상태를 검사하고 조작할 수 있어 디버깅과 테스트가 용이

어노테이션(Annotation)

  • 메타데이터 제공 : 클래스, 메서드, 필드 등에 추가 정보를 제공하여 런타임이나 컴파일 시에 특정 동작을 유발시킬 수 있음
  • 간결한 코드 : 코드의 가독성과 유지보수성 향상. 기존 코드에 쉽게 추가하여 기능 확장 가능
  • 프레임워크 통합 : 스프링 같은 프레임워크와 함께 사용하여 설정을 간소화하고 자동화
 

단점

리플렉션(Reflection)

  • 성능 저하: 리플렉션은 일반적인 메서드 호출보다 더 많은 비용이 들기 때문에 성능이 저하될 수 있음
  • 보안 이슈: 리플렉션은 접근 제어를 무시할 수 있어 보안 문제가 발생할 수 있음

어노테이션(Annotation)

  • 과도한 사용: 어노테이션을 남용하면 코드가 복잡해지고 의존성이 증가할 수 있음
  • 제한된 기능: 어노테이션 자체는 동작을 정의하지 않으며, 실제 동작을 수행하려면 별도의 처리기가 필요
  • 런타임 오버헤드: 리플렉션과 함께 사용되는 경우 성능 오버헤드가 발생할 수 있음.
 
Share article

송승현의 블로그