[Spring Basic] Java Reflection API
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Hello World");
}
}
위와 같은 소스코드 파일이 주어졌을 때, cmd에서 실행시키려면 해당 파일이 위치한 위치에서
java Main.java 를 입력하면 된다.
여기서 앞에 위치한 java는 java.exe로 자바 인터프리터를 의미하며, 인터프리터가 Main.java의 main메서드를 호출해 소스코드가 실행된다. (main메서드는 static메서드이기에 객체를 생성하지 않고 사용할 수 있다.)
로컬 위치에 파일이 있는 경우에는 위처럼 진행할 수 있는데, 파일의 위치가 로컬 말고 다른 위치에 있다면 어떻게 해야할까?
원격 프로그램을 실행시키려면 브라우저와 WAS (Web Application Server, 여기서는 Tomcat) 가 필요하다.
먼저 WAS에서 해당하는 원격 프로그램을 등록하고, 특정 URL과 프로그램을 연결시켜 놓는다.
위 작업이 마친 상태에서 브라우저에서 해당 URL을 입력해 등록된 원격 프로그램을 실행할 수 있다.
이렇게 연결시킨 후에는, http:// ~~~~ /hello URL에서 해당 프로그램을 실행시킬 수 있게 된다.
@Controller
public class Hello {
@RequestMapping("/hello")
private void main() {
System.out.println("Hello");
}
}
위와 같이 코드를 작성한 후 실행해보면, 메서드가 static이 아니지만 잘 실행된다.
이유는, 브라우저에서 호출할 때 WAS가 객체를 생성하는 과정이 있다.
객체가 생성되기에 static키워드가 붙지 않아도 메서드를 사용할 수 있게 된다.
(인스턴스 메서드는 static변수와 인스턴스변수 모두 사용할 수 있고, static메서드는 static변수만 사용할 수 있다.)
RequestMapping으로 연결된 경우는 접근제어자에 상관없이 외부에서 호출할 수 있도록 함을 의미한다.
접근제어자를 Private를 설정해도 Reflection API (java.lang.reflect)를 사용해 클래스에 대한 정보를 얻고 다룰 수 있도록 설계되어있어 객체를 생성할 수 있다.
Class name = Class.forName("Hello");
(위와 같이 특정 클래스에 대한 정보를 얻어온다.)
Class name = Class.forName("Hello");
Hello hello = (Hello)name.newInstance();
얻어온 후에는 newInstance메서드를 사용해 객체를 생성할 수 있다.
Class name = Class.forName("Hello");
Hello hello = (Hello)name.newInstance(); // 객체 생성
Method main = name.getDeclaredMethod("main"); // 메서드 얻어오기
main.setAccessible(true); // private메서드를 호출가능하게 만듦
main.invoke(hello); // private메서드 호출
객체를 생성한 후에는 private로 지정된 메서드에도 접근할 수 있다.
이렇듯 Java Reflection API 는 프로그램 실행 중 자신의 구조를 알아내거나 변경할 수 있는 기능을 제공한다.
java.lang.reflect 패키지 내부에 포함되어있고, 해당 패키지는 필드, 메서드, 생성자 등 여러 정보를 가져오는 기능을 제공한다.
Reflection API의 핵심은 자바의 접근 제어자를 우회해서 사용할 수 있다는 점이다.
private던 protected던 상관없이 사용할 수 있어 강력하지만, 그렇다고 해서 private 등 접근 제어자가 아무 의미가 없다는 건 아니다.
생각해보자. private는 클래스 내부에서만 사용할 필드 또는 메서드를 지정할 때 사용된다.
이를 통해 내부 구현을 숨기고 외부에는 필요한 인터페이스만을 노출시키는다.
물론 Reflection API를 사용하면 접근 제어를 우회해서 클래스 내부 정보를 조작할 수 있다.
Reflection API의 구현을 보면 알 수 있듯, 오버헤드가 어느 정도 있는 편이다.
실제 개발에서는 디버깅, 테스팅, 동적 조작 등 필요한 경우에만 Reflection API로 접근 제어를 우회해서 사용하고, 그렇지 않은 경우는 private를 그대로 유지하는 방식을 사용한다.
스프링 프레임워크에서는 DI, AOP, Data Binding 과정을 수행할 때 Reflection API를 사용해 코드의 확장성을 극대화한다.
1. @Autowired로 DI를 수행할 때 내부적으로 Reflection API를 사용해서 클래스 정보를 분석하고 필드에 주입해준다.
2. 로깅을 수행하기 위해 AOP를 적용할 때 @Before 애너테이션을 사용했다고 하자. 스프링은 이런 AOP 설정을 처리할 때 Reflection API를 사용해 메서드 정보를 읽어오고 프록시 객체를 생성한 후 메서드를 호출한다.
3. 웹 요청 파라미터를 엔티티나 DTO에 바인딩 할 때도 Reflection API가 사용된다.
'Spring > Spring' 카테고리의 다른 글
[Spring Basic] 파라미터의 변환과 검증 (0) | 2022.06.24 |
---|---|
[Spring Basic] DispatcherServlet (0) | 2022.06.23 |
[Spring Basic] 리다이렉트와 포워드 (0) | 2022.05.12 |
[Spring Basic] 서블릿과 JSP (0) | 2022.05.05 |
[Spring Basic] 서블릿과 출력 (0) | 2022.04.13 |
댓글
이 글 공유하기
다른 글
-
[Spring Basic] DispatcherServlet
[Spring Basic] DispatcherServlet
2022.06.23 -
[Spring Basic] 리다이렉트와 포워드
[Spring Basic] 리다이렉트와 포워드
2022.05.12 -
[Spring Basic] 서블릿과 JSP
[Spring Basic] 서블릿과 JSP
2022.05.05 -
[Spring Basic] 서블릿과 출력
[Spring Basic] 서블릿과 출력
2022.04.13