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

1-1. 프로젝트 생성

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. 프로젝트 생성

>> ex02 패키지 생성

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

2-2. Retention. RetentionPolicy
- @Retention

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

@Override 는 source 을 사용하고, @Transactional은 runtime 을 사용함
2-3. Target. ElementType

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



추가)
@Target
, @Retention
, @interface
에 대한 설명
@Target
: 이 어노테이션은 해당 어노테이션이 적용될 수 있는 대상(타입)을 지정하는 역할을 합니다.@Target(ElementType.TYPE)
는 이 어노테이션이 클래스, 인터페이스, 열거형(enum) 또는 애노테이션에만 적용될 수 있다는 것을 의미합니다.ElementType
의 종류에는TYPE
,FIELD
,METHOD
,PARAMETER
,CONSTRUCTOR
등이 있으며, 이를 통해 어노테이션이 적용될 수 있는 위치를 정의할 수 있습니다.
@Retention
: 이 어노테이션은 어노테이션이 어느 시점까지 유지될지를 지정합니다.- 이때 UserController에 A개발자가 사용하기 원하는 매서드가 없으면
@Retention(RetentionPolicy.RUNTIME)
은 어노테이션이 런타임까지 유지된다는 것을 의미합니다. 즉, 런타임 시 리플렉션을 사용하여 이 어노테이션에 접근할 수 있다는 것입니다.RetentionPolicy
에는SOURCE
,CLASS
,RUNTIME
세 가지가 있습니다.SOURCE
: 컴파일 시점까지만 어노테이션이 유지되고, 클래스 파일에서는 사라집니다.CLASS
: 컴파일된 클래스 파일에 어노테이션 정보가 포함되지만, 런타임에는 사용되지 않습니다.RUNTIME
: 컴파일된 클래스 파일에 어노테이션 정보가 포함되며, 런타임에서도 어노테이션 정보를 사용할 수 있습니다.
@interface
: 자바에서 어노테이션을 정의할 때 사용되는 키워드입니다.public @interface Controller { }
은Controller
라는 어노테이션을 정의하는 구문입니다.- 어노테이션은 인터페이스와 유사하게 동작하지만, 메타데이터를 제공하는 데 사용됩니다.

⇒ getMapping 어노테이션으로 들어가서 확인해 보면 여기는 ElementType.METHOD 라고 되어있다. → @getMapping 은 매서드에 적용되는 어노테이션이라는 걸 알 수 있다.
추가_ ElementType.TYPE )



⇒ Controller 어노테이션으로 들어가서 확인해보면 ElementType.TYPE 으로 되어있다.
→ @Controller 는 매서드에 적용되는 어노테이션이라는 걸 알 수 있다.

→ @Repository 마찬가지로 클래스에 사용하는 어노테이션임을 알 수 있다.

>> 이렇게 내가 직접 만든 RequestMapping 어노테이션이 만들어졌다!
→ ElementType.METHOD : 매서드에 적용할 수 있는 어노테이션
→ RetentionPolicy.RUNTIME : 런타임. 실행시에 이 어노테이션 정보를 분석하거나 처리할 수 있음

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