리플렉션이란?
- 리플렉션
→ 속을 비추다 (코드의 내부를 들여다보는 것)
보통 런타임에 리플렉션이 일어난다. (모든걸 탐색하게 함)
코드 실행전 컴파일시 분석하게 하기 위해서는 어노테이션을 활용하게 할 수 있음.
어노테이션을 활용하기 위해서는 행위를 정의해야한다. 다만, 사람이 나무를 수리한다고 했을 때 나무의 높이에 따라
수리한다
를 제외한 행위는 다르게 정의될 수 있다.
어노테이션이란?
JVM 이 보는 힌트. 주석같은 역할을 한다.
1. 리플렉션 예제
리플렉션을 사용하지 않는 코드

1.1 컨트롤러 생성
먼저,
UserController
라는 클래스를 만들어 로그인과 회원가입 기능을 제공하는 메서드를 정의합니다.package ex01;
public class UserController {
public void login(){
System.out.println("login 호출됨");
}
public void join(){
System.out.println("join 호출됨");
}
}
1.2 App 클래스 생성
이제,
App
클래스에서 사용자가 입력한 URL에 따라 해당 메서드를 호출하도록 코드를 작성해봅시다.package ex01;
public class App {
public static void main(String[] args) {
String path = "/login";
UserController uc = new UserController();
if(path.equals("/login")) {
uc.login();
}else if (path.equals("/join")) {
uc.join();
}
}
}
1.3 실행

String path = "/login";
를 join 으로 바꾸면
🎈 이 코드는 단순히
path
변수를 통해 /login
또는 /join
경로에 맞춰 UserController
의 메서드를 호출합니다. 그러나 이런 방식은 확장성이 떨어집니다. 새로운 메서드가 추가될 때마다 App
클래스도 수정해야 하기 때문입니다.
2. 리플렉션 활용
🎈 참고로 리플렉션은 순서 보장이 되지 않는다.
아래 코드는
UserController
클래스의 메서드를 리플렉션을 사용해 탐색하고, 그 이름을 출력합니다.2.1 UserController 생성
public class UserController {
public void login(){
System.out.println("login 호출됨");
}
public void join(){
System.out.println("join 호출됨");
}
}
2.2 App 클래스 생성
import java.lang.reflect.Method;
public class App {
public static void main(String[] args) {
UserController uc = new UserController();
Method[] methods = uc.getClass().getDeclaredMethods();
for (Method mt : methods) {
System.out.println(mt.getName());
}
}
}
Method[] methods = uc.getClass().getDeclaredMethods();
를 통해 UserController 안에 있는 메서드의 이름을 조회할 수 있다. (실행도 가능하다!)
- 실행하는 코드

mt.invoke(uc);
를 사용하기 위해서는 Exception
이 필요함.(매개변수로 넣은 uc 안에 메서드가 존재하지 않을 수 있기 때문에)
2.3 어노테이션 정의
어노테이션을 사용하면 메서드 이름 대신 어노테이션 값을 기준으로 동적으로 메서드를 호출할 수 있다.
먼저
RequestMapping
이라는 어노테이션을 정의해 본다.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(); // String 타입의 uri 를 넣을 수 있음.
}

소스 : 컴파일시 , 런타임 : 런타임시

이 엘레멘트가 붙을 수 있는 위치를 의미한다.
2.4 어노테이션 적용 및 최종 코드
public class UserController {
@RequestMapping(uri = "/login")
public void login(){
System.out.println("login 호출됨");
}
@RequestMapping(uri = "/join")
public void join(){
System.out.println("join 호출됨");
}
}
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();
Method[] methods = uc.getClass().getDeclaredMethods();
for (Method mt : methods) {
Annotation anno = mt.getDeclaredAnnotation(RequestMapping.class);
RequestMapping rm = (RequestMapping) anno;
// 이렇게 통합할 수 있음
// RequestMapping rm = mt.getAnnotation(RequestMapping.class);
if (rm == null) break;
if(rm.uri().equals(path)){
mt.invoke(uc);
}
}
}
}
위 코드에서는 어노테이션을 사용해 각 메서드가 어떤 URL 경로와 매핑되는지를 정의한 후, 런타임에 이 매핑 정보를 바탕으로 메서드를 호출한다.
path
변수만 바꾸면 어떤 메서드든 호출할 수 있게 되며, 새로운 메서드가 추가되더라도 App
클래스는 수정할 필요가 없다.결론
이번 포스팅에서는 스프링 프로젝트에서 자주 사용되는 어노테이션이 어떻게 동작하는지 살펴보며, 리플렉션에 대해 알아보았다.
리플렉션을 통해 어노테이션의 실제 사용 방식과 그 동작 원리를 더 깊이 이해할 수 있었으며, 이를 바탕으로 기존에 활용하던 코드를 분석하고 개선할 수 있는 방법도 배울 수 있었다.
앞으로 어노테이션을 더 효과적으로 활용하기 위해 이번에 배운 내용을 프로젝트에 적용해 보면 좋을것이다.
Share article