Notice
Recent Posts
Recent Comments
Link
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
Tags
more
Archives
Today
Total
관리 메뉴

희동이네

[Java] Reflection과 Annotation 본문

Java

[Java] Reflection과 Annotation

희동누나 2022. 10. 28. 17:01
더보기

타입을 안다? 해당 타입이 코드에 읽혔다

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

 

 

 

실행결과