[Java] πŸͺž Reflectionμ΄λž€?

Sangho HanΒ·3일 μ „
2

β˜•οΈΒ Java

λͺ©λ‘ 보기
22/22
post-thumbnail

🏁 μ„œλ‘ 

JPAμ—μ„œ Entity에 κΈ°λ³Έ μƒμ„±μžκ°€ ν•„μˆ˜μ μΈ μ΄μœ μ— λŒ€ν•΄μ„œ μ•Œμ•„λ³΄λ˜ 쀑, Java Reflection μ΄λΌλŠ” κ°œλ…μ— λŒ€ν•΄μ„œ μ•Œκ²Œ λ˜μ—ˆλ‹€.

쑰사λ₯Ό ν•˜λ‹€ λ³΄λ‹ˆ, Spring ν”„λ ˆμž„μ›Œν¬μ—μ„œ ν•΅μ‹¬μ μœΌλ‘œ μ‚¬μš©ν•˜κ³  μžˆλŠ” μžλ°”μ˜ κΈ°λŠ₯μ΄λΌλŠ” 것을 μ•Œκ²Œ λ˜μ—ˆκ³ , 쑰금 더 μžμ„Ένžˆ μ•Œμ•„λ³΄λŠ” 게 쒋을 것 κ°™μ•„ 글을 μž‘μ„±ν•˜κ²Œ λ˜μ—ˆλ‹€.


πŸͺž Java Reflectionμ΄λž€?

μžλ°” λ¦¬ν”Œλ ‰μ…˜μ€ ν”„λ‘œκ·Έλž¨μ΄ μ‹€ν–‰ 쀑(runtime)에 자기 μžμ‹ μ„ 듀여닀보고 λΆ„μ„ν•˜λŠ” κΈ°λŠ₯이닀.
μ½”λ“œκ°€ 마치 κ±°μšΈμ„ 보듯 μžμ‹ μ˜ λ‚΄λΆ€ ꡬ쑰(클래슀, λ©”μ„œλ“œ, ν•„λ“œ λ“±)λ₯Ό νŒŒμ•…ν•˜κ³ , μ‹¬μ§€μ–΄λŠ” κ·Έ ꡬ쑰λ₯Ό λ³€κ²½ν•˜κ±°λ‚˜ μ‘°μž‘ν•  수 있게 ν•΄μ£ΌλŠ” κ°•λ ₯ν•œ 도ꡬ이닀.

'Reflection'μ΄λΌλŠ” 이름은 'λ°˜μ‚¬', 'μ„±μ°°'μ΄λΌλŠ” λœ»μ—μ„œ μœ λž˜ν•˜μ˜€λ‹€.

λ¦¬ν”Œλ ‰μ…˜μ˜ JVM λ™μž‘ 원리

이λ₯Ό λ”μš± μžμ„Ένžˆ μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„œλŠ”, 컴파일 μ‹œμ μ˜ JVM λ™μž‘ 원리λ₯Ό μ•Œμ•„λ³Ό ν•„μš”κ°€ μžˆλ‹€.

1단계: 컴파일 (.java β†’ .class)

예λ₯Ό λ“€μ–΄, Person.java λΌλŠ” 파일이 컴파일되면 Person.class 파일이 μƒμ„±λœλ‹€.

이 .class 파일 μ•ˆμ—λŠ” λ‹¨μˆœνžˆ μ‹€ν–‰ κ°€λŠ₯ν•œ λ°”μ΄νŠΈμ½”λ“œ(Bytecode)만 μžˆλŠ” 것이 μ•„λ‹ˆλΌ, ν΄λž˜μŠ€μ— λŒ€ν•œ λͺ¨λ“  메타데이터(Metadata) κ°€ μΌμ’…μ˜ μ„€κ³„λ„μ²˜λŸΌ κΈ°λ‘λ˜μ–΄ μžˆλ‹€.

  • 클래슀 이름, λΆ€λͺ¨ 클래슀, κ΅¬ν˜„ν•œ μΈν„°νŽ˜μ΄μŠ€ 정보
  • ν•„λ“œ(멀버 λ³€μˆ˜)의 이름, νƒ€μž…, μ ‘κ·Ό μ œμ–΄μž(public, private λ“±)
  • λ©”μ„œλ“œμ˜ 이름, νŒŒλΌλ―Έν„°, 리턴 νƒ€μž…, μ ‘κ·Ό μ œμ–΄μž
  • μƒμ„±μž 정보, μ–΄λ…Έν…Œμ΄μ…˜ 정보 λ“±

2단계: 클래슀 λ‘œλ”© (Loading)

μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‹€ν–‰λ˜λ‹€κ°€ Person 클래슀λ₯Ό 처음 μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” μ‹œμ (예: new Person() λ˜λŠ” Class.forName("Person"))이 였면, JVM의 클래슀 λ‘œλ”(Class Loader) κ°€ λ™μž‘ν•œλ‹€.

  1. 클래슀 λ‘œλ”λŠ” 파일 μ‹œμŠ€ν…œμ—μ„œ Person.class νŒŒμΌμ„ μ°Ύμ•„ μ½μ–΄μ˜¨λ‹€.
  2. .class νŒŒμΌμ— λ‹΄κΈ΄ λ°”μ΄νŠΈμ½”λ“œμ™€ 메타데이터λ₯Ό νŒŒμ‹±(뢄석)ν•œλ‹€.
  3. 이 λΆ„μ„λœ 정보λ₯Ό JVM λ©”λͺ¨λ¦¬μ˜ λ©”μ„œλ“œ μ˜μ—­(Method Area)에 μ €μž₯ν•©λ‹ˆλ‹€. (Java 8 μ΄ν›„λ‘œλŠ” Metaspace μ˜μ—­μ„ μ˜λ―Έν•¨)
    -> λ©”μ„œλ“œ μ˜μ—­μ€ λͺ¨λ“  μŠ€λ ˆλ“œκ°€ κ³΅μœ ν•˜λŠ” μ˜μ—­μœΌλ‘œ, 클래슀의 '섀계도 원본'이 λ³΄κ΄€λ˜λŠ” 곳이라고 생각할 수 μžˆλ‹€.

3단계: Class 객체 생성

클래슀 정보가 λ©”μ„œλ“œ μ˜μ—­μ— λ‘œλ“œλ  λ•Œ, JVM은 이 ν΄λž˜μŠ€μ— λŒ€ν•œ μœ μΌν•œ java.lang.Class 객체λ₯Ό ν•˜λ‚˜ μƒμ„±ν•΄μ„œ νž™(Heap) μ˜μ—­μ— μ €μž₯ν•œλ‹€.

  • person.getClass(), Person.class, Class.forName("Person") λ“±μœΌλ‘œ μ–»λŠ” 객체가 λ°”λ‘œ 이 νž™ μ˜μ—­μ— μžˆλŠ” Class 객체이닀.
    -> 이 Class κ°μ²΄λŠ” λ©”μ„œλ“œ μ˜μ—­μ— μ €μž₯된 μ‹€μ œ λ©”νƒ€λ°μ΄ν„°λ‘œ μ ‘κ·Όν•  수 μžˆλŠ” 리λͺ¨μ»¨ λ˜λŠ” κ²Œμ΄νŠΈμ›¨μ΄ 역할을 ν•œλ‹€.

4단계: λ¦¬ν”Œλ ‰μ…˜ API μ‹€ν–‰

이후 λ¦¬ν”Œλ ‰μ…˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λ©΄ JVM λ‚΄λΆ€μ—μ„œλŠ” μ•„λž˜μ™€ 같은 일이 λ²Œμ–΄μ§„λ‹€.

// personClassλŠ” νž™(Heap)에 μžˆλŠ” Class 객체λ₯Ό κ°€λ¦¬ν‚€λŠ” μ°Έμ‘° λ³€μˆ˜
Class<?> personClass = Class.forName("Person");

// 1. getDeclaredField("age") 호좜
// 2. JVM은 personClass 리λͺ¨μ»¨μ„ 톡해 λ©”μ„œλ“œ μ˜μ—­(Method Area)에 μ €μž₯된
//    Person 클래슀의 메타데이터λ₯Ό 뒀짐
// 3. 'age'λΌλŠ” μ΄λ¦„μ˜ ν•„λ“œ 정보λ₯Ό 찾아냄
// 4. 이 정보λ₯Ό λ°”νƒ•μœΌλ‘œ 'Field' 객체λ₯Ό νž™(Heap)에 μƒμ„±ν•˜μ—¬ λ°˜ν™˜
Field ageField = personClass.getDeclaredField("age");

// Field 객체의 set()μ΄λ‚˜ Method 객체의 invoke()λ₯Ό ν˜ΈμΆœν•˜λ©΄
// JVM은 이 객체듀이 κ°€μ§„ 정보λ₯Ό μ΄μš©ν•΄ λ©”μ„œλ“œ μ˜μ—­μ˜ μ‹€μ œ μ½”λ“œλ‚˜
// νž™μ— μžˆλŠ” μ‹€μ œ μΈμŠ€ν„΄μŠ€μ˜ λ©”λͺ¨λ¦¬ μ£Όμ†Œμ— μ ‘κ·Όν•˜μ—¬ 값을 μ‘°μž‘ν•©λ‹ˆλ‹€.

πŸ› οΈ Reflection API의 μ£Όμš” κΈ°λŠ₯κ³Ό ν…ŒμŠ€νŠΈ μ½”λ“œ

λ¦¬ν”Œλ ‰μ…˜μ˜ 거의 λͺ¨λ“  μž‘μ—…μ€ ν΄λž˜μŠ€κ°€ λ‘œλ“œλ  λ•Œ JVM이 νž™ μ˜μ—­μ— μ €μž₯ν•˜λŠ” java.lang.Class λΌλŠ” νŠΉλ³„ν•œ κ°μ²΄μ—μ„œλΆ€ν„° μ‹œμž‘λœλ‹€. ν•΄λ‹Ή 객체만 μ–»μœΌλ©΄ 클래슀의 λͺ¨λ“  정보λ₯Ό 캐낼 μˆ˜κ°€ μžˆλ‹€.

ν…ŒμŠ€νŠΈμš© Person 클래슀

public class Person {
    public String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void sayHello() {
        System.out.println("Hello, my name is " + name);
    }

    private void whisperAge() {
        System.out.println("Actually... I'm " + age + " years old.");
    }
}
  • public ν•„λ“œ(name)
  • private ν•„λ“œ(age)
  • public λ©”μ„œλ“œ(sayHello)
  • private λ©”μ„œλ“œ(whisperAge)

핡심 κΈ°λŠ₯κ³Ό 예제 μ½”λ“œ

μ•„λž˜ μ½”λ“œλŠ” Person 클래슀λ₯Ό λ¦¬ν”Œλ ‰μ…˜μœΌλ‘œ λΆ„μ„ν•˜κ³  μ‘°μž‘ν•˜λŠ” 과정을 보여쀀닀.

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionExample {
    public static void main(String[] args) throws Exception {
        // 1. 클래슀 정보 κ°€μ Έμ˜€κΈ° (Class 객체 λ‘œλ“œ)
        // λ¬Έμžμ—΄ μ΄λ¦„λ§ŒμœΌλ‘œ 클래슀의 λͺ¨λ“  정보λ₯Ό 담은 객체λ₯Ό μ–»μŠ΅λ‹ˆλ‹€.
        Class<?> personClass = Class.forName("Person");
        System.out.println("1. λ‘œλ“œλœ 클래슀: " + personClass.getName());

        // 2. μƒμ„±μžλ₯Ό μ΄μš©ν•΄ 객체(μΈμŠ€ν„΄μŠ€) λ§Œλ“€κΈ°
        // νŒŒλΌλ―Έν„° νƒ€μž…(String, int)을 μ§€μ •ν•˜μ—¬ μ›ν•˜λŠ” μƒμ„±μžλ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.
        Constructor<?> constructor = personClass.getConstructor(String.class, int.class);
        // 찾은 μƒμ„±μžλ‘œ μƒˆ μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“­λ‹ˆλ‹€. 'new Person("μƒν˜Έ", 25)'κ³Ό κ°™μŠ΅λ‹ˆλ‹€.
        Object personObject = constructor.newInstance("μƒν˜Έ", 25);
        System.out.println("2. μƒμ„±λœ 객체: " + personObject);

        // 3. ν•„λ“œ(멀버 λ³€μˆ˜)에 μ ‘κ·Όν•˜κ³  κ°’ λ³€κ²½ν•˜κΈ°
        // 'age'λΌλŠ” μ΄λ¦„μ˜ ν•„λ“œλ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€. privateμ΄λ―€λ‘œ getDeclaredField()λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
        Field ageField = personClass.getDeclaredField("age");
        // private ν•„λ“œμ— μ ‘κ·Όν•˜λ €λ©΄ μ ‘κ·Ό μ œν•œμ„ ν’€μ–΄μ•Ό ν•©λ‹ˆλ‹€.
        ageField.setAccessible(true);
        // personObject의 age ν•„λ“œ 값을 26으둜 λ³€κ²½ν•©λ‹ˆλ‹€.
        ageField.set(personObject, 26);
        System.out.println("3. λ³€κ²½λœ private ν•„λ“œ κ°’(age): " + ageField.get(personObject));

        // 4. λ©”μ„œλ“œ ν˜ΈμΆœν•˜κΈ°
        // 'whisperAge'λΌλŠ” μ΄λ¦„μ˜ λ©”μ„œλ“œλ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€. privateμ΄λ―€λ‘œ getDeclaredMethod()λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
        Method whisperMethod = personClass.getDeclaredMethod("whisperAge");
        // private λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜κΈ° μœ„ν•΄ μ ‘κ·Ό μ œν•œμ„ ν’‰λ‹ˆλ‹€.
        whisperMethod.setAccessible(true);
        // personObject의 whisperAge() λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.
        System.out.print("4. 호좜된 private λ©”μ„œλ“œ: ");
        whisperMethod.invoke(personObject);
    }
}

μ‹€ν–‰ κ²°κ³Ό

1. λ‘œλ“œλœ 클래슀: Person
2. μƒμ„±λœ 객체: Person@1b6d3586  // (객체의 ν•΄μ‹œμ½”λ“œ)
3. λ³€κ²½λœ private ν•„λ“œ κ°’(age): 26
4. 호좜된 private λ©”μ„œλ“œ: Actually... I'm 26 years old.

이처럼 λ¦¬ν”Œλ ‰μ…˜μ„ μ‚¬μš©ν•˜λ©΄ λ¬Έμžμ—΄ μ΄λ¦„λ§ŒμœΌλ‘œ 클래슀λ₯Ό μ œμ–΄ν•  수 μžˆλ‹€. 심지어 private μ ‘κ·Ό μ œν•œκΉŒμ§€ μš°νšŒν•˜μ—¬ λ‚΄λΆ€ μƒνƒœλ₯Ό 읽고 μˆ˜μ •ν•  수 μžˆλ‹€.


πŸš€ λ¦¬ν”Œλ ‰μ…˜μ΄ μ‚¬μš©λ˜λŠ” κ³³

λ¦¬ν”Œλ ‰μ…˜μ€ 일반적인 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ½”λ“œλ³΄λ‹€λŠ”, νŠΉμ • κΈ°μˆ μ΄λ‚˜ κ·œμ•½μ— μ˜μ‘΄ν•˜μ§€ μ•ŠλŠ” λ²”μš©μ μΈ κΈ°λŠ₯을 λ§Œλ“€μ–΄μ•Ό ν•˜λŠ” ν”„λ ˆμž„μ›Œν¬λ‚˜ λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ 핡심적인 역할을 ν•˜κ²Œ λœλ‹€.

1. Springμ—μ„œ μ˜μ‘΄μ„± μ£Όμž… (DI)

μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬μ˜ 핡심적인 κΈ°λŠ₯인 IoC(μ œμ–΄μ˜ μ—­μ „) μ»¨ν…Œμ΄λ„ˆμ™€ DI(μ˜μ‘΄μ„± μ£Όμž…)λŠ” λ¦¬ν”Œλ ‰μ…˜ 기술 μ—†μ΄λŠ” κ΅¬ν˜„μ΄ λΆˆκ°€λŠ₯ν•˜λ‹€.

μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ UserService 객체에 UserRepositoryλ₯Ό μ£Όμž…(@Autowired)ν•˜λŠ” 과정을 λ¦¬ν”Œλ ‰μ…˜ κ΄€μ μ—μ„œ μ‚΄νŽ΄λ³΄λ©΄ μ•„λž˜μ™€ κ°™λ‹€.

  1. μ»΄ν¬λ„ŒνŠΈ μŠ€μΊ”: μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‹œμž‘λ˜λ©΄, μŠ€ν”„λ§μ€ @Component, @Service, @Repository 같은 μ–΄λ…Έν…Œμ΄μ…˜μ΄ 뢙은 ν΄λž˜μŠ€λ“€μ„ μ°ΎλŠ”λ‹€.
    -> 이 κ³Όμ •μ—μ„œ 클래슀의 메타데이터λ₯Ό 읽기 μœ„ν•΄ λ¦¬ν”Œλ ‰μ…˜μ΄ μ‚¬μš©λœλ‹€.
  1. Bean μΈμŠ€ν„΄μŠ€ 생성: μŠ€ν”„λ§μ€ μ°Ύμ•„λ‚Έ 클래슀λ₯Ό λ°”νƒ•μœΌλ‘œ 객체(Bean)λ₯Ό 생성해야 ν•œλ‹€.
    -> μ΄λ•Œ λ¦¬ν”Œλ ‰μ…˜μ˜ Constructor.newInstance()λ₯Ό μ‚¬μš©ν•˜μ—¬ 각 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“ λ‹€.
  1. μ˜μ‘΄μ„± μ£Όμž… μ‹€ν–‰: UserService Bean을 μƒμ„±ν•œ ν›„, μŠ€ν”„λ§μ€ ν•΄λ‹Ή 클래슀λ₯Ό μŠ€μΊ”ν•˜μ—¬ @Autowired μ–΄λ…Έν…Œμ΄μ…˜μ΄ 뢙은 ν•„λ“œ(userRepository)λ₯Ό μ°ΎλŠ”λ‹€.
  1. ν•„λ“œ 정보 뢄석: λ¦¬ν”Œλ ‰μ…˜μœΌλ‘œ userRepository ν•„λ“œμ˜ νƒ€μž…μ΄ UserRepositoryλΌλŠ” 것을 μ•Œμ•„λ‚Έλ‹€.
  1. Bean μ°ΎκΈ° 및 μ£Όμž…: μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ—μ„œ UserRepository νƒ€μž…μ˜ Bean을 찾은 λ’€, λ¦¬ν”Œλ ‰μ…˜μ˜ Field.set() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ UserService 객체의 userRepository ν•„λ“œμ— ν•΄λ‹Ή Bean을 μ£Όμž…ν•œλ‹€.
    -> μ΄λ•Œ ν•„λ“œκ°€ private이라도 field.setAccessible(true)λ₯Ό 톡해 κ°•μ œλ‘œ 값을 μ„€μ •ν•  수 μžˆλ‹€.
@Service
@RequiredArgsConstructor
public class UserService {
    private final JwtService jwtService;
    private final UserValidator userValidator;
    private final ApplicationEventPublisher eventPublisher;
    private final UserRepository userRepository;
    private final DeleteReasonRepository deleteReasonRepository;
    private final CategoryRepository categoryRepository;
    private final CommentRepository commentRepository;
    private final MobileRepository mobileRepository;
    
    ...

πŸ§‘πŸ»β€πŸ’» μ΄λŸ¬ν•œ νŠΉμ„± λ•Œλ¬Έμ—, μœ„μ™€ 같이 private으둜 μ„€μ •ν•˜μ—¬λ„ μ˜μ‘΄μ„± μ£Όμž…μ„ μ •μƒμ μœΌλ‘œ 해쀄 μˆ˜κ°€ μžˆλ‹€!

2. JPA λ“± ORM ν”„λ ˆμž„μ›Œν¬

JPA κ΅¬ν˜„μ²΄(주둜 ν•˜μ΄λ²„λ„€μ΄νŠΈ)κ°€ DBμ—μ„œ μ‘°νšŒν•œ 데이터λ₯Ό Entity 객체둜 λ§Œλ“œλŠ” 과정은 μ•„λž˜μ™€ κ°™λ‹€.

  1. 데이터 쑰회: userRepository.findById(1L) 같은 λ©”μ„œλ“œκ°€ 호좜되면, ν•˜μ΄λ²„λ„€μ΄νŠΈλŠ” DB둜 SELECT * FROM USERS ... 쿼리λ₯Ό 보내 데이터λ₯Ό μ‘°νšŒν•œλ‹€.
  1. Entity 객체 생성: 쑰회된 κ²°κ³Όλ₯Ό 담을 Entity 객체의 μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€μ–΄μ•Ό ν•œλ‹€. ν•˜μ§€λ§Œ ν•˜μ΄λ²„λ„€μ΄νŠΈλŠ” κ°œλ°œμžκ°€ μ–΄λ–€ μƒμ„±μžλ₯Ό λ§Œλ“€μ–΄ 뒀을지 μ „ν˜€ μ•Œ μˆ˜κ°€ μ—†λŠ” μƒνƒœμ΄λ‹€.
  1. κΈ°λ³Έ μƒμ„±μž 호좜: κ·Έλž˜μ„œ ν•˜μ΄λ²„λ„€μ΄νŠΈλŠ” κ°€μž₯ μ•ˆμ „ν•˜κ³  ν™•μ‹€ν•œ 방법인 κΈ°λ³Έ μƒμ„±μžλ₯Ό λ¦¬ν”Œλ ‰μ…˜μœΌλ‘œ ν˜ΈμΆœν•˜μ—¬ 'ν…… 빈' 객체λ₯Ό λ¨Όμ € μƒμ„±ν•œλ‹€. (User.class.getConstructor().newInstance())
  1. ν•„λ“œμ— κ°’ λ§€ν•‘: μƒμ„±λœ 객체의 각 ν•„λ“œμ— λ¦¬ν”Œλ ‰μ…˜(Field.set())을 μ‚¬μš©ν•˜μ—¬ DBμ—μ„œ κ°€μ Έμ˜¨ 값을 ν•˜λ‚˜μ”© μ±„μ›Œ λ„£λŠ”λ‹€. id 컬럼 값은 id ν•„λ“œμ—, name 컬럼 값은 name ν•„λ“œμ— μ„€μ •ν•˜λŠ” 식이닀.

3. JUnit λ“± ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬

JUnit이 @Test μ–΄λ…Έν…Œμ΄μ…˜ ν•˜λ‚˜λ§Œ 뢙이면 μ•Œμ•„μ„œ ν…ŒμŠ€νŠΈλ₯Ό μ‹€ν–‰ν•΄μ£ΌλŠ” 것도 λ¦¬ν”Œλ ‰μ…˜ 덕뢄이라 ν•  수 μžˆλ‹€.

  1. ν…ŒμŠ€νŠΈ λ©”μ„œλ“œ 검색: JUnit μ‹€ν–‰κΈ°λŠ” μ§€μ •λœ ν…ŒμŠ€νŠΈ 클래슀(MyTest.class)의 λͺ¨λ“  λ©”μ„œλ“œλ₯Ό λ¦¬ν”Œλ ‰μ…˜μœΌλ‘œ μŠ€μΊ”ν•œλ‹€.
  1. μ–΄λ…Έν…Œμ΄μ…˜ 확인: μŠ€μΊ”ν•œ λ©”μ„œλ“œλ“€ 쀑 @Test μ–΄λ…Έν…Œμ΄μ…˜μ΄ λΆ™μ–΄μžˆλŠ” λ©”μ„œλ“œλ₯Ό μ°Ύμ•„ λͺ©λ‘μœΌλ‘œ λ§Œλ“ λ‹€. λ˜ν•œ @BeforeEach, @DisplayName λ“± λ‹€λ₯Έ μ–΄λ…Έν…Œμ΄μ…˜ 정보도 μ΄λ•Œ ν•¨κ»˜ μˆ˜μ§‘ν•œλ‹€.
  1. ν…ŒμŠ€νŠΈ μ‹€ν–‰: JUnit은 μ°Ύμ•„λ‚Έ ν…ŒμŠ€νŠΈ λ©”μ„œλ“œ λͺ©λ‘μ„ μˆœνšŒν•˜λ©° λ¦¬ν”Œλ ‰μ…˜μ˜ Method.invoke()λ₯Ό μ‚¬μš©ν•΄ 각 λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•œλ‹€.
    -> Method.invoke() λŠ” Java Reflection API의 핡심 κΈ°λŠ₯ 쀑 ν•˜λ‚˜λ‘œ, λŸ°νƒ€μž„μ— νŠΉμ • 객체의 λ©”μ„œλ“œλ₯Ό λ™μ μœΌλ‘œ ν˜ΈμΆœν•  수 있게 ν•΄μ£ΌλŠ” λ©”μ„œλ“œμ΄λ‹€.

πŸ§‘πŸ»β€πŸ’» 이 덕뢄에 κ°œλ°œμžκ°€ ν…ŒμŠ€νŠΈ λ©”μ„œλ“œλ₯Ό 일일이 ν˜ΈμΆœν•˜λŠ” main λ©”μ„œλ“œλ₯Ό λ§Œλ“€ ν•„μš”κ°€ μ—†μ–΄μ§„λ‹€!


⚠️ μœ μ˜μ‚¬ν•­

λ¦¬ν”Œλ ‰μ…˜ κΈ°λŠ₯을 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ‹¨μ—μ„œ ν™œμš©ν•  일은 잘 μ—†μœΌλ‚˜, ν˜Ήμ‹œ λͺ¨λ₯΄λ‹ˆ μœ μ˜μ‚¬ν•­μ— λŒ€ν•΄μ„œ 짚고 λ§ˆλ¬΄λ¦¬ν•˜λ©΄ 쒋을 λ“―ν•˜λ‹€.

1. μ„±λŠ₯ μ €ν•˜

λ¦¬ν”Œλ ‰μ…˜μ„ ν†΅ν•œ λ©”μ„œλ“œ ν˜ΈμΆœμ€ 일반적인 λ©”μ„œλ“œ ν˜ΈμΆœλ³΄λ‹€ 훨씬 느린데, JVM이 컴파일 μ‹œμ μ— μ΅œμ ν™”λ₯Ό ν•  수 μ—†μœΌλ©° λŸ°νƒ€μž„μ— 클래슀, λ©”μ„œλ“œ, ν•„λ“œμ˜ 정보λ₯Ό ν•˜λ‚˜ν•˜λ‚˜ μ°Ύμ•„λ‹€λ‹ˆλŠ” κ³Όμ •μ—μ„œ μƒλ‹Ήν•œ μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

λ•Œλ¬Έμ— 그럴 일은 잘 μ—†κ² μ§€λ§Œ, μ„±λŠ₯에 λ―Όκ°ν•œ λ‘œμ§μ— λ¦¬ν”Œλ ‰μ…˜ APIλ₯Ό ν¬ν•¨ν•˜λŠ” 것은 μ§€μ–‘ν•˜λŠ” 게 μ’‹λ‹€.

2. μΊ‘μŠν™” 파괴

λ¦¬ν”Œλ ‰μ…˜μ˜ setAccessible(true) μ˜΅μ…˜μ€ private으둜 μ„ μ–Έλœ ν•„λ“œλ‚˜ λ©”μ„œλ“œμ— λŒ€ν•œ 접근을 κ°€λŠ₯ν•˜κ²Œ ν•˜λ―€λ‘œ, 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ˜ 핡심 원칙 쀑 ν•˜λ‚˜μΈ μΊ‘μŠν™”λ₯Ό λ¬΄λ„ˆλœ¨λ¦¬κ²Œ λœλ‹€.

κ·Έλ ‡κΈ° λ•Œλ¬Έμ— ν”„λ ˆμž„μ›Œν¬ λ‹¨μ—μ„œμ™€ 같이 ν•„μˆ˜μ μΈ 상황이 μ•„λ‹ˆλΌλ©΄ μ‚¬μš©μ„ μ§€μ–‘ν•΄μ•Ό ν•œλ‹€.

3. 컴파일 νƒ€μž„ μ•ˆμ •μ„±

λ¦¬ν”Œλ ‰μ…˜μ€ 주둜 λ¬Έμžμ—΄(String)둜 ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œμ˜ 이름을 μ§€μ •ν•˜μ—¬ μ‚¬μš©ν•˜λ©°, μ΄λŠ” 컴파일러의 νƒ€μž… 체크 κΈ°λŠ₯을 무λ ₯ν™”μ‹œμΌœ λŸ°νƒ€μž„ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€λŠ” μš”μΈμ΄ λœλ‹€.


🎬 마무리

μ§€κΈˆκΉŒμ§€ Java의 Reflection에 λŒ€ν•΄μ„œ μ•Œμ•„λ³΄μ•˜λ‹€.
κ·Έλ™μ•ˆμ—λŠ” Spring ν”„λ ˆμž„μ›Œν¬κ°€ μ–΄λ–€ μ‹μœΌλ‘œ Bean을 μƒμ„±ν•˜κ³  μ£Όμž…ν•˜λŠ”μ§€ μ•Œμ§€ λͺ» ν–ˆλŠ”λ°, 이번 기회둜 쑰금 더 이해할 수 있게 λ˜μ—ˆλ˜ 것 κ°™λ‹€.

μ•žμœΌλ‘œλ„ λ‚΄κ°€ μ‚¬μš©ν•˜λŠ” κΈ°μˆ λ“€μ˜ λ™μž‘ 원리에 λŒ€ν•΄ μ΄ν•΄ν•˜λ„λ‘ λ”μš± λ…Έλ ₯ν•΄μ•Όκ² λ‹€.

μ°Έκ³ ν•œ λΈ”λ‘œκ·Έ

  1. https://jeongkyun-it.tistory.com/225

  2. https://curiousjinan.tistory.com/entry/java-reflection-explain

  3. https://steady-coding.tistory.com/609

  4. https://velog.io/@blackbean99/SpringBoot-%EB%A6%AC%ED%94%8C%EB%A0%89%EC%85%98%EC%9C%BC%EB%A1%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-Autowired

profile
μ•ˆλ…•ν•˜μ„Έμš”. λΉ„μ¦ˆλ‹ˆμŠ€λ₯Ό μ΄ν•΄ν•˜λŠ” λ°±μ—”λ“œ 개발자, ν•œμƒν˜Έμž…λ‹ˆλ‹€.

0개의 λŒ“κΈ€