Java 리플렉션: 프레임워크의 기본

Quiz

이 퀴즈에 답을 할 수 있다면 이글을 안읽어도 된다.!

  1. object.getClass()가 뭘 리턴하나요?
  2. Class 객체가 메모리 구조에서 어디에 저장되나요?
  3. 다음 TestInterface 인터페이스를 구현할 수 있나요?
    public class TestClass {
        private String s1;
        private String s2;
        private int i1;
           
        void action() {
            print
        }
    }
    
    public Interface TestInterface {
    
        // 문자열 속성 개수
        int countStringField(Object class);
    
        // object에 'action`이라는 이름이 들어간 메소드 실행
        void doAction(Object class);
    }
       
    

What is Refraction

Refraction은 영문 사전에서는 ‘투명’, ‘반사'을 뜻한다. Java에서 Refraction은 응용 프로그램의 런타임의 동작을 검사하고 수정할 수 있는 기능을 제공한다. 이렇게 말하면 처음보는 사람은 ‘그래서 어쩌라는거지'라는 생각을 가질 수 있다.

예시로 Spring에서 Converter(Object Mapper)를 써보셨다면 이해가 잘되실 것이다.

Spring Container이 뭐지 하시는 분들은 @Component, @Service, @Controller같은 어노테이션이 있는 Class를 인스턴스화 시켜서 Bean으로 등록해주고 @Autowired를 사용해서 Bean을 꺼내 쓰는 것을 말한다. BeanFactory(Spring Container) 구현하기 위해서는 Refraction이라는 것이 필요하다. 왜냐하면 어노테이션을 읽어 Bean 등록도 꺼내주는 것도 해줄 수 있기 때문이다.

그외에도 Refraction은 여러곳에서 쓰인다.

  • JUnit – reflection을 이용하여 @Test 어노테이션이 붙은 메소드를 찾아 실행한다.
  • Spring – 의존성 주입, Dependency Injection
  • Hibernate - Entity Mapping, 메소드명으로 쿼리 자동 생성 등등 …

Reflaction은 컴파일 단계가 아니라 런타임 단계에서 객체를 읽어 인스턴스화하고, 메소드 호출 필드값을 즉, Reflaction을 런타임시 마법같은 일을 알아낼 수 있다.

내용이 큰만큼 긴호흡으로 천천히 읽어주셨으면 좋겠다

Refraction 크게 보기

Java에서 Refraction은 매우 파워풀한 개념이다.
일반적인 프로그래밍에서는 거의 사용하지 않지만 J2EE 프레임 워크 중추적인 역할을 한다.

그외에도 JUnit, Spring, Tomcat, Hibernate등 수 없이 많은 프레임워크에서 사용한다.

Refaction도 단점이 없는 것은 아니다.

일반적으로 Interface와 Class에 바로 엑세스 할 수 있는 일반적인 프로그래밍에서는 안사용하는게 맞다.

  • 성능 저하 : 리플렉션을 사용하게되면 클래스를 클래스를 그냥 사용하는 것 이외에도 클래스의 위치를 찾기위해 경로를 스캔 및 클래스 해석등의 추가적인 작업들이 있어 성능이 저하된다.
  • 보안 문제 : 접근제한자 ‘private’ 같ㅌ이 외부에서 값을 접근 못하게 했지만 리플렉션은 그걸 무시하고 접근할 수 있기에 애플리케이션이 비정상적으로 동작하게 할 위험이 있습니다.
  • 유지보수 문제 리플렉션 코드를 이해하고 디버깅하기가 어렵다.
    코드가 컴파일과정중에 문제를 찾을 수 없기에 런타임중 버그가 발생할 확률이 올라간다.

Refaction 메모리 구조로 보기

Java는 모든 객체는 기본 유형 또는 참조형입니다. (이말이 이해가 안된다면 사전지식이 부족할 수 있습니다. 두개의 차이를 알아보신후에 마저 읽어보세요)

모든 참조형 객체는 java.lang.Object를 기본으로 상속받도록 되어있습니다.
class에 extends Object가 안되어 있는 생략해도 되기 떄문입니다. ObjectgetClass()이라는 메소드를 가지고 있고 getClass()는 Return으로 java.lang.Class 객체를 리턴한다.

class Dobby { }

public class program {
    public static void main(String[] args) {
        Dobby.class.getFields();
        
        Dobby dobby = new Dobby();
        dobby.getClass().getFields();
    }
}

짐작하겠지만, java.lang.Class가 모든 Refaction 작업의 시작점이 된다.
java.lang.Class가 뭐길레 Refaction의 시작점이라고 하는걸까?

이전에 작성했던 Java 생태계와 실행 제대로 알고 있나?을 보셨거나, Java 실행과정을 잘 안다면 Method 메모리 영역을 알 것이다.
(모르겠다면 Java 생태계와 실행 제대로 알고 있나?를 보시길.. )

Java는 실행될때 .class 파일들은 Class 로더에 의해서 Method 메모리에 Class 객체로 올라게가 된다. Class 객체에는 클래스 수준의 정보(인터페이스, 클래스 이름, 부모 클래스, 메소드, 변수, 등)가 들어있다.

이제 우리는 Class 객체를 얻는방법 .getClass와 Class 객체에 어떤 정보가 들어있는지 안다. 그 정보들을 꺼내서 쓰는 방법만 알면 된다.!!

마무리!

Java에서 Reflaction이 어떻게 동작하는지 알아봤다.
API 사용하는 방법에 관한 부분은 웹 검색하면 널렸다.!!
그래도 깔끔하게 정리된 곳을 원한다면 여기를 들어가면 된다. 영어로 되어있지만 위의 내용들을 이해했다면 소스코드만으로도 사용하는데 무리가 없다.

comments powered by Disqus