희동이네
[Java] Reflection과 Annotation 본문
타입을 안다? 해당 타입이 코드에 읽혔다
String타입으로 com.ssafy.servlet을 읽어왔다
클래스영역 -> 메소드가 올라감 즉, 함수들이 올라가는데 타입이 적재된다.
Person p = new Person(); 일 때 만약 Person의 타입을 모른다면?
언제 사용? 코드 작성 시점에는 클래스타입을 몰랐을 때 사용. 동적으로(이미 프로그램 실행된 이후) 클래스를 가져와서 사용할 경우.
프레임워크를 만날 때 혁신적인 기술임.
reflection 자체가 클래스타입을 모르기 때문에
Class<?> c1 = 클래스이름.class <-- 클래스타입 모르기 때문에 못 씀
Class<?> c2 = 객체.getClass() <-- 이미 객체를 생성했다는 게 reflection이 필요없음
Class<?> c2 = Class.forName(String name) <-- 문자열은 패키지 경로. 패키지 경로로 클래스 정보 가져오기
타입을 모를 때 런타임 때 클래스의 정보 얻어오고 -> 생성자 찾기 -> 메소드 찾기 -> 필드 변경 ...
https://velog.io/@yeon/Reflection%EC%9D%B4%EB%9E%80 참고
Dog를 reflection 으로 필드, 메소드 호출..
Test02
Prefereces > java > compiler > Store info~ 체크 > 다시 build > 재실행하면 이전에 식별하지 못했던 파라미터명 arg0이 name, age라고 파라미터명 뜬다!
이제 파라미터명을 식별할 수 있게 됐다.
getMethods() : private, 부모클래스까지 다 가져옴
getDeclaredMethods() : private아니고, 내 클래스만 가져옴.
스프링컨트롤러 -> 다 순회할 필요 없으므로 getMethods() 보다는 getDeclaredMethods()를 주로 사용. annotation 정보를 얻어올 수도 있다.
Test03
클래스 로딩 -> 객체 생성 -> 함수호출
(1) 객체생성 : getDeclaredConstructor() 어차피 오버로딩 돼있으므로 파라미터에 따라서 알아서 매칭해서 가져온다. 이걸로 생성자 만들 수 있음 -> 만든 생성자로 객체 생성까지 가능
(2) 함수호출 : 함수.invoke()
어노테이션
Deprecated : 더이상 쓰지X
SupreeWarnings : 경고 이제X
기본 어노테이션 : 컴파일러가 돌아가는 영역에서 돌아감.
메타 어노테이션 : 어노테이션을 위한 어노테이션
사용자 정의 어노테이션 : 위들을 이용해서 만들 어노테이션
- 어노테이션이 가질 항목들. 함수의 형태를 띄나 변수의 역할을 함.
- 함수(의 형태이지만)가 아니고 속성일 뿐이니까 파라미터 있으면 안 됨
- 요소의 반환타입은 기초자료형(or 의 배열), String, Class, enum 만 됨. 즉, 나중에 만들어진 타입(Person)은 불가
@interface Peson{
String name(); // 사실은 함수가 아니므로 파라미터, throws가 없음
int age();
// 변수타입 변수명
}
Person이라는 포스트잇에
name:
age:
이라고 있는 것...
Marker annotaion
- 붙여있는 존재만으로서 식별 (존재유무만으로)
- 값은 없음
Single annotation
- "" 값이 하나만 들어감
Full annotation
- "" "" 값이 여러 개 들어감
default가 있으면 값 안 들어가도 오류 안 남.
mappings : url을 키값으로(애노테이션으로부터 읽어온 ) value에 obj와 m을 묶어서 넣음.
사용자가 url을 읽어오면 매핑된 cam읽어서 메소드를 실행함
F3누르면서 스프링 보자..
RequestMapping
- Target : 어디에 어노테이션을 붙일 수 있는지 지정한다. ex TYPE이 Class면? 클래스는 사용자가 정의한 자료형.
- 위 예시는 @RequestMapping이 메소드에만 붙어있기 때문에 영역을 METHOD로 지정한다.
- Retention : 얼마나 오래 어노테이션 유지할지?
- @Retention이 Runtime으로 돼있어야 리플렉션을 통해 접근 가능 @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String[] value() default {};
RequestMethod[] method() default {};
}
RequestMethod
public enum RequestMethod {
GET, POST, PUT, DELETE
}
CtrlAndMethod
- 함수호출에 필요한 정보를 모아논 객체/DTO
- Object : BoardController, Method : list() writeform() delete()
public class CtrlAndMethod {
private Object target;
private Method method;
public CtrlAndMethod(Object target, Method method) {
this.target = target;
this.method = method;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
}
BoardController
public class BoardController {
@RequestMapping(value="/board/list", method=RequestMethod.GET)
public void list() {
System.out.println("목록 조회용");
}
@RequestMapping("/board/writeForm")
public void writeForm() {
System.out.println("글쓰기 폼용");
}
@RequestMapping(value="/board/delete", method=RequestMethod.DELETE)
public void delete() {
System.out.println("글삭제용");
}
}
loginController
public class LoginController {
@RequestMapping("/login/login")
public void login() {
System.out.println("login 메서드 실행됨");
}
}
MemberController
public class MemberController {
@RequestMapping("/member/join")
public void join() {
System.out.println("join 메서드 실행됨");
}
}
Test
public class Test {
private static Map<String, CtrlAndMethod> mappings = new HashMap<>();
static {
Class<?>[] clzArr = { BoardController.class, MemberController.class, LoginController.class };
try {
for (Class<?> clz : clzArr) { // Componet-scan 역할
Object obj = clz.getDeclaredConstructor().newInstance(); // 객체 생성
Method[] arr = clz.getDeclaredMethods(); // 클래스에 선언되어 있는 메서드 얻기
for (Method m : arr) {
RequestMapping rm = m.getAnnotation(RequestMapping.class); // 메서드에 선언되어 있는 RequestMapping 어노테이션 얻기
// getAnnotation을 테스트해보는 코드
// Annotation[] aa = m.getAnnotations(); // RequestMapping 붙어있는 어노테이션들 다 출력해보기
// for (Annotation a : aa) {
// System.out.println(a);
// }
// 만약, 메서드에 RequestMapping 선언이 없다면 다음 반복 실행
if (rm == null) continue;
// 맵의 키를 RequestMapping에 입력된 value 속성 설정
// 맵의 값으로 메서드를 실행하기 위해 객체와 메서드 참조를 CtrlAndMethod 객체에 입력하여 설정
for (String url : rm.value()) {
mappings.put(url, new CtrlAndMethod(obj, m));
}
}
}
} catch (Exception e) {
System.out.println("클래스 정보 읽는 중 에러발생");
e.printStackTrace();
}
}
public void execute() {
// System.out.println(mappings); // 등록된 mappings들을 확인
Scanner sc = new Scanner(System.in);
try {
while (true) {
System.out.print("호출할 URI 입력 : ");
String url = sc.nextLine();
if (url.equals("quit")) break;
CtrlAndMethod cam = mappings.get(url);
if (cam == null) {
System.out.println("등록된 URL이 아닙니다.");
continue;
}
cam.getMethod().invoke(cam.getTarget()); // cam에 등록되어 잇는 메서드 실행
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("프로그램이 종료되었습니다.");
sc.close();
}
public static void main(String[] args) {
try {
Test t = new Test();
t.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
}
실행결과

'Java' 카테고리의 다른 글
| [Java] 그래프 표현(인접행렬, 인접리스트, 간선배열)및 탐색(DFS, BFS) | 백준 1260 풀이 (0) | 2022.10.17 |
|---|---|
| [Servlet] GET/POST방식으로 데이터 전송하기 (0) | 2022.08.31 |
| [Java] Outer Loop 탈출법, break 사용범위 (0) | 2022.08.19 |
| [Java] 자릿수 출력하기 (0) | 2022.08.05 |
| [Java] 자바 기초 03 | 반복문, break, continue (0) | 2022.07.05 |