Skip to content

Latest commit

 

History

History
101 lines (70 loc) · 3.17 KB

박성우.md

File metadata and controls

101 lines (70 loc) · 3.17 KB

reflection은 거울에 비친 상을 의미한다.

자바에서는 class가 실체 JVM 메모리 영역이 거울의 영역이다.

  1. 자바에서 컴파일러가 자바 코드를 바이트 코드로 바꾼다.
  2. 클래스 로더는 바이트 코드를 JVM의 메모리에 저장한다.
  3. 리플렉션은 JVM 메모리에 저장된 데이터를 사용하는 기술이다.

리플렉션이 제공하는 기술

  1. 생성자를 통한 객체 생성
  2. 필드 정보 조회
  3. 필드 값 변경
  4. 메서드 정보 조회

리플렉션을 왜 쓸까?

리플렉션은 주로 프레임워크와 라이브러리에서 사용한다.

프레임워크나 라이브러리는 컴파일 시점 전까지 사용자가 생성한 객체의 타입을 알 수 없다.

이러한 문제를 동적으로 사용하기위해 리플렉션을 사용한다.

기본 생성자가 필요한 경우

기본 생성자를 통해 객체를 만들고 값을 넣어주기 위해서 필요하다.

리플렉션의 단점

  • 컴파일 시점이 아니라 런타임 시점에서 클래스를 분석하기 때문에, 일반 메서드 호출보다 성능이 훨씬 떨이진다.
  • 컴파일 시점에서 타입 체크 기능을 사용할 수 없다.
  • 내부를 노출해서 추상화를 파괴한다.

실제로 Reflection이 어떻게 사용될까?

1. 사용자가 정의한 @Controller 를 스프링에서 Bean 객체로 생성하는 방법

예시 코드)

public class ControllerScanner {

    private final Reflections reflections;

    public ControllerScanner(Object... basePackages) {
        reflections = new Reflections(basePackages);
    }
	
    public List<Object> getControllers() {
				// 1
        Set<Class<?>> controllerClasses = reflections.getTypesAnnotatedWith(Controller.class);

        return controllerClasses.stream()
                .map(this::createController)
                .collect(Collectors.toList());
    }

    private Object createController(Class<?> controllerClass) {
        try {
						// 2
            return controllerClass.getConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException |
                 InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}
  1. @Controller 어노테이션이 붙은 클래스들을 모두 찾는다.
  2. Class.getConstructor 를 사용하여 생성자를 찾고, newInstance 를 통해 인스턴스를 생성한다.

위 코드는 스프링 코드가 아니고 내가 작성한 코드라서 정확하지 않다.

2. 역직렬화 과정에서 기본 생성자 사용

class Person {
    private String name;

		// 생략
}

위와 같은 dto가 존재할 때

class RequestDeserializer {

    // JSON 형식의 바디를 받아서 해당 클래스 객체로 역직렬화하는 메서드
    public static <T> T deserializeBody(String body, Class<T> clazz) throws Exception {
        T obj = clazz.getDeclaredConstructor().newInstance();

        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, fieldValue);
	   }
}

위처럼 필드 값에 직접 값을 대입한다.