Reflection & Annotation
Annotation
Annotation | 설명 |
@Retention | Annotation 유지 범위 지정 (컴파일러, 런타임 등) |
@Target | Annotation 적용 대상 지정 (메서드, 클래스 등) |
@Documented | 문서화 도구(Javadoc)에서 어노테이션 포함 여부 |
@Inherited | 상속될 수 있는 Annotation 지정 |
@Repeatable | 같은 Annotation을 여러 번 사용할 수 있도록 허용 |
@RequestMapping
package ex02;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequestMapping {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
- 해당 Annotation이 Runtime에도 사라지지 않고 유지되게 해주며, Reflection이 이를 활용할 수 있게 된다
@Target(ElementType.METHOD)
- 전용 Type을 결정
- 여기서 Method Type을 설정하면, Method 전용 Annotation이 된다
- 이렇게 Method로 설정이 되어있다면 해당 Annotation은 Method드 위에 붙여야 한다
String URI();
- RequestMapping Annotation의 속성값
- 따라서 Annotation이 사용될때 속성값 역시 받아올 수 있다
Reflection
Dispatcher
package ex02;
import java.lang.reflect.Method;
public class Dispatcher {
UserController con;
public Dispatcher(UserController con) {
this.con = con;
}
public void routing(String path) { // /login
Method[] methods = con.getClass().getMethods();
for (Method method : methods) {
RequestMapping rm = method.getAnnotation(RequestMapping.class);
if (rm == null) continue; // 다음 for문으로 바로 넘어감
if (rm.value().equals(path)) {
try {
method.invoke(con);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
👉 Reflection 구현하는 핵심 코드
Method[] methods = con.getClass().getMethods();
➡
Method[]
: java.lang.reflect에 선언된 메서드를 저장할 수 있는 객체 배열➡
.getClass()
: 클래스의 메타 데이터를 조회➡
.getMethods()
: 조회된 클래스에 선언된 모든 public
메서드를 가져온다👉 Reflection 구현 완성
for (Method method : methods) {
RequestMapping rm = method.getAnnotation(RequestMapping.class);
if (rm == null) continue; // 다음 for문으로 바로 넘어감
if (rm.value().equals(path)) {
try {
method.invoke(con);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
➡
RequestMapping rm = method.getAnnotation(RequestMapping.class)
: RequestMapping Annotation이 있는 클래스에서 가져온 메서드를 rm에 담는다➡
for each
구문에서 배열에 담긴 메서드를 순회➡
rm.value()
이 검색중인 (path)
요청값이랑 비교➡ 비교값이 메서드 이름과 일치하면
method.invoke(con)
으로 해당 메서드 실행UserController
⚠ 직접 만든 Annotation을 사용하기 위해서는 같은 Package 안에 존재해야 한다
package ex02;
public class UserController {
@RequestMapping("/login")
public void login() {
System.out.println("login call");
}
@RequestMapping("/join")
public void join() {
System.out.println("join call");
}
@RequestMapping("/logout")
public void logout() {
System.out.println("logout call");
}
@RequestMapping("/userinfo")
public void userinfo() {
System.out.println("userinfo call");
}
}
App
- Dispatcher를 Heap에 띄우고, 그 안에 UserController를 담는다
package ex02;
public class App {
public static void main(String[] args) {
Dispatcher ds = new Dispatcher(new UserController());
ds.routing("/login");
ds.routing("/join");
ds.routing("/logout");
ds.routing("/userinfo");
}
}
✅ 출력 결과
C:\workspace\tools\jdk-21\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2024.3.2.1\lib\idea_rt.jar=53858:C:\Program Files\JetBrains\IntelliJ IDEA 2024.3.2.1\bin" -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath C:\workspace\spring_lec\ref\out\production\ref ex02.App
login call
join call
logout call
userinfo call
Process finished with exit code 0
Share article