[Java] 8 리플렉션 (Reflection) 과 스프링 어노테이션 (Annotation)

스프링 어노테이션을 사용하기 전에 리플렉션을 먼저 알아보자
김호정's avatar
Aug 18, 2024
[Java] 8 리플렉션 (Reflection) 과 스프링 어노테이션 (Annotation)
 
reflection을 알아야 스프링을 아는 것이다, reflection은 스프링에서 많이 쓰인다.
notion image
 

1-1. 프로젝트 생성

 
notion image

1-2. Code

App

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(); } } }
 

UserController

package ex01; // B 개발자 public class UserController { public void login(){ System.out.println("login 호출됨"); } public void join(){ System.out.println("join 호출됨"); } public void userInfo(){ System.out.println("userinfo 호출됨"); } }
 
 
  • B개발자가 만든 UserController를 A개발자가 만든 App에 가져와 적용시킨다.
  • 예를 들어 userInfo 같은 매서드가 없으면
  • A개발자는 B개발자에게 userInfo 매서드를 만들어 달라고 해서 생성되고 나서
  • App에서 사용할 수 있다.
  • else if (path.equals(”/userinfo”)) 추가해서 사용.
  • 이렇게 되면 각 회사의 많이 요청이 있을 때마다, B개발자는 추가해줘야한다.
 
  • 이렇게 안하기 위해 만든게 “Reflection” 이다 !
 

2-1. 프로젝트 생성

 
notion image
>> ex02 패키지 생성
notion image
>> ex02 패키지 → RequestMapping 생성 (Annotation 체크)
 
RequestMapping
notion image
 
 

2-2. Retention. RetentionPolicy

  • @Retention
notion image
 
@Retention →
RetentionPolicy.SOURCE는 컴파일 시에 분석. → 컴파일때 봐야하는 힌트
RetentionPolicy.RUNTIME은 런타임 시에 분석. → 런타임때 봐야하는 힌트
즉,
source를 달면 → 움직이기 전에! 실행전에 깃발을 확인 할 수 있음 → 실행전에 어노테이션을 확인
runtime을 달면 움직인 후에! 깃발을 확인함
notion image
 
💡
@Override 는 source 을 사용하고, @Transactional은 runtime 을 사용함

2-3. Target. ElementType

 
notion image
 
ElementType.field → ‘변수(필드)’위에 붙일 수 있음
ElementType.constructor → ‘생성자’위에 붙일 수 있음 (@builder 같이)
ElementType.method → ‘매서드’ 위에 붙일 수 있음
 
notion image
notion image
notion image
 
추가)
 
💡

@Target, @Retention, @interface에 대한 설명

  1. @Target: 이 어노테이션은 해당 어노테이션이 적용될 수 있는 대상(타입)을 지정하는 역할을 합니다.
      • @Target(ElementType.TYPE)는 이 어노테이션이 클래스, 인터페이스, 열거형(enum) 또는 애노테이션에만 적용될 수 있다는 것을 의미합니다.
      • ElementType의 종류에는 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR 등이 있으며, 이를 통해 어노테이션이 적용될 수 있는 위치를 정의할 수 있습니다.
  1. @Retention: 이 어노테이션은 어노테이션이 어느 시점까지 유지될지를 지정합니다.
      • 이때 UserController에 A개발자가 사용하기 원하는 매서드가 없으면
      • @Retention(RetentionPolicy.RUNTIME)은 어노테이션이 런타임까지 유지된다는 것을 의미합니다. 즉, 런타임 시 리플렉션을 사용하여 이 어노테이션에 접근할 수 있다는 것입니다.
      • RetentionPolicy에는 SOURCE, CLASS, RUNTIME 세 가지가 있습니다.
        • SOURCE: 컴파일 시점까지만 어노테이션이 유지되고, 클래스 파일에서는 사라집니다.
        • CLASS: 컴파일된 클래스 파일에 어노테이션 정보가 포함되지만, 런타임에는 사용되지 않습니다.
        • RUNTIME: 컴파일된 클래스 파일에 어노테이션 정보가 포함되며, 런타임에서도 어노테이션 정보를 사용할 수 있습니다.
  1. @interface: 자바에서 어노테이션을 정의할 때 사용되는 키워드입니다.
      • public @interface Controller { }Controller라는 어노테이션을 정의하는 구문입니다.
      • 어노테이션은 인터페이스와 유사하게 동작하지만, 메타데이터를 제공하는 데 사용됩니다.
 
 
notion image
 
⇒ getMapping 어노테이션으로 들어가서 확인해 보면 여기는 ElementType.METHOD 라고 되어있다. → @getMapping 은 매서드에 적용되는 어노테이션이라는 걸 알 수 있다.
 
추가_ ElementType.TYPE )
 
notion image
notion image
 
 
notion image
⇒ Controller 어노테이션으로 들어가서 확인해보면 ElementType.TYPE 으로 되어있다.
→ @Controller 는 매서드에 적용되는 어노테이션이라는 걸 알 수 있다.
 
notion image
 
→ @Repository 마찬가지로 클래스에 사용하는 어노테이션임을 알 수 있다.
 
notion image
>> 이렇게 내가 직접 만든 RequestMapping 어노테이션이 만들어졌다!
→ ElementType.METHOD : 매서드에 적용할 수 있는 어노테이션
→ RetentionPolicy.RUNTIME : 런타임. 실행시에 이 어노테이션 정보를 분석하거나 처리할 수 있음
notion image
 

2-4. Code

ex02. App

package ex02; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; // reflect 의 Method import 해주기 public class App { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { String path = "/board/save-form"; UserController uc = new UserController(); Method[] methods = uc.getClass().getDeclaredMethods(); //uc.getClass(); //System.out.println(uc.getClass()); /* Method[] methods = uc.getClass().getDeclaredMethods(); //System.out.println(uc.getClass().getDeclaredMethods()); // uc 클래스안에 어떤 매서드가 있는지 리턴해줌 // java.lang.reflect.Method[] 타입으로 리턴받음 for(Method mt : methods){ System.out.println(mt.getName()); // 이게 REFLECTION. 실행시에 그 클래스를 분석해서 확인하는 것!!! mt.invoke(uc); // 매서드를 호출하는데 그 이름을 정확하게 몰라도 호출할 수 있다...! // 모든 나무(모든 매서드)를 다 실행시킴 } */ for(Method mt : methods) { Annotation anno = mt.getDeclaredAnnotation(RequestMapping.class); RequestMapping rm = (RequestMapping) anno; if(rm == null) { System.out.println("404 not found"); break;// 어노테이션이 없으면 아무것도 하지말고 break 해라 } if(rm.uri().equals(path)){ mt.invoke(uc); } } } }

ex02.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(); // 변수 못적고 무조건 매서드만 적을 수 있다. -> 배열이다. // 배열이어서 컨트롤러에서 @RequestMapping 사용할 때 // @RequestMapping(uri = "/join, /login") 이렇게 여러개도 적을 수 있다. }

ex02.UserController

package ex02; public class UserController { @RequestMapping(uri = "/board/save-form") public void saveForm(){ System.out.println("save form 호출됨"); } @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 호출됨"); } }
 
 
Share article

keepgoing