스프링 빈이 등록되는 과정의 원리 - 리플렉션

태그
Spring

노트

  • 면접 보다가 스프링의 IoC/DI 핵심기술과 관련해 꼬리질문을 받다가.. 왜 여기까진 생각해보지 못했을까 회고하며 정리해보자.
    • 일반적으로 익히 다들 다 알고 있듯이 스프링 컨테이너는 Bean을 등록받고 이를 필요로 하는 클래스에 주입 해준다.
    • 크게 Bean을 주입 받는 방법으로 생성자로 주입받는 방식과 필드에 주입받는 방식 두가지로 나뉜다.
    • 이 중 필드에 주입 받는 방식의 경우 @Autowired 라는 어노테이션을 명시하여 주입받도록 한다.
  • @Autowired 어노테이션으로 명시된 필드에 대해 어떻게 인스턴스를 주입하는 것일까?
    • 바로 리플렉션(Reflection)을 사용해 주입한다.
    • 어노테이션을 생성하게 되면 다음과 같이 생성할 수 있다. 스프링의 @Autowired 어노테이션을 예로 들어보자
    • @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { /** * Declares whether the annotated dependency is required. * <p>Defaults to {@code true}. */ boolean required() default true; }
    • 주석과 동등하게 어노테이션은 기본적으로 런타임에서 참조할 수 없다. 컴파일되어 클래스 파일로 변환되어 바이트 코드내에는 정보가 존재하지만, 런타임내 메모리에는 어노테이션과 관련한 정보가 남아있지 않다.
    • @Retention 어노테이션에 RetentionPolicy.RUNTIME 정책으로 변경하게되면, 런타임내에서도 어노테이션 정보를 참조할 수 있게 된다.
    • @Target 어노테이션은 해당 어노테이션이 어떤 곳에 쓰일 수 있을지를 정할 수 있다. @Autowired는 생성자, 메서드, 파라미터, 필드, 또다른 어노테이션에 참조할 수 있도록 정의하였다.
    • 위와 같은 어노테이션의 기능을 사용하면, @Autowired가 붙은 클래스내 필드에 대해 직접 접근해서 정보를 가져오고, 인스턴스를 생성해서 해당 필드에 주입할 수 있다.
    • 예를 들면, 다음과 같이 어떤 클래스를 리플렉션을 사용해서 생성할 수 있다.
    • Class<?> fooClass = Class.forName("com.example.service"); Constructor<?> constructor = fooClass.getConstructor(null); Object instance = constructor.newInstance();
    • 그리고 다음과 같이 특정 클래스에 존재하는 어떠한 어노테이션이 존재하는지 알아낼 수 있다.
    • Class.forName("com.example.service").getAnnotations()
    • 따라서 위와 같은 접근 방식들을 적절히 활용하면, @Autowired 처럼 Bean 주입을 할 수 있을 것이다.

요약

📌
요약: 리플렉션