JPAμμ Entityμ κΈ°λ³Έ μμ±μκ° νμμ μΈ μ΄μ μ λν΄μ μμ보λ μ€, Java Reflection
μ΄λΌλ κ°λ
μ λν΄μ μκ² λμλ€.
μ‘°μ¬λ₯Ό νλ€ λ³΄λ, Spring νλ μμν¬μμ ν΅μ¬μ μΌλ‘ μ¬μ©νκ³ μλ μλ°μ κΈ°λ₯μ΄λΌλ κ²μ μκ² λμκ³ , μ‘°κΈ λ μμΈν μμ보λ κ² μ’μ κ² κ°μ κΈμ μμ±νκ² λμλ€.
μλ° λ¦¬νλ μ μ νλ‘κ·Έλ¨μ΄ μ€ν μ€(runtime)μ μκΈ° μμ μ λ€μ¬λ€λ³΄κ³ λΆμνλ κΈ°λ₯μ΄λ€.
μ½λκ° λ§μΉ κ±°μΈμ λ³΄λ― μμ μ λ΄λΆ ꡬ쑰(ν΄λμ€, λ©μλ, νλ λ±)λ₯Ό νμ νκ³ , μ¬μ§μ΄λ κ·Έ ꡬ쑰λ₯Ό λ³κ²½νκ±°λ μ‘°μν μ μκ² ν΄μ£Όλ κ°λ ₯ν λꡬμ΄λ€.'Reflection'μ΄λΌλ μ΄λ¦μ 'λ°μ¬', 'μ±μ°°'μ΄λΌλ λ»μμ μ λνμλ€.
μ΄λ₯Ό λμ± μμΈν μ΄ν΄νκΈ° μν΄μλ, μ»΄νμΌ μμ μ JVM λμ μ리λ₯Ό μμλ³Ό νμκ° μλ€.
μλ₯Ό λ€μ΄, Person.java
λΌλ νμΌμ΄ μ»΄νμΌλλ©΄ Person.class
νμΌμ΄ μμ±λλ€.
μ΄ .class
νμΌ μμλ λ¨μν μ€ν κ°λ₯ν λ°μ΄νΈμ½λ(Bytecode)λ§ μλ κ²μ΄ μλλΌ, ν΄λμ€μ λν λͺ¨λ λ©νλ°μ΄ν°(Metadata)
κ° μΌμ’
μ μ€κ³λμ²λΌ κΈ°λ‘λμ΄ μλ€.
- ν΄λμ€ μ΄λ¦, λΆλͺ¨ ν΄λμ€, ꡬνν μΈν°νμ΄μ€ μ 보
- νλ(λ©€λ² λ³μ)μ μ΄λ¦, νμ , μ κ·Ό μ μ΄μ(
public
,private
λ±)- λ©μλμ μ΄λ¦, νλΌλ―Έν°, λ¦¬ν΄ νμ , μ κ·Ό μ μ΄μ
- μμ±μ μ 보, μ΄λ Έν μ΄μ μ 보 λ±
μ ν리μΌμ΄μ
μ΄ μ€νλλ€κ° Person
ν΄λμ€λ₯Ό μ²μ μ¬μ©ν΄μΌ νλ μμ (μ: new Person()
λλ Class.forName("Person")
)μ΄ μ€λ©΄, JVMμ ν΄λμ€ λ‘λ(Class Loader)
κ° λμνλ€.
- ν΄λμ€ λ‘λλ νμΌ μμ€ν μμ
Person.class
νμΌμ μ°Ύμ μ½μ΄μ¨λ€..class
νμΌμ λ΄κΈ΄ λ°μ΄νΈμ½λμ λ©νλ°μ΄ν°λ₯Ό νμ±(λΆμ)νλ€.- μ΄ λΆμλ μ 보λ₯Ό JVM λ©λͺ¨λ¦¬μ λ©μλ μμ(Method Area)μ μ μ₯ν©λλ€. (Java 8 μ΄νλ‘λ Metaspace μμμ μλ―Έν¨)
-> λ©μλ μμμ λͺ¨λ μ€λ λκ° κ³΅μ νλ μμμΌλ‘, ν΄λμ€μ 'μ€κ³λ μλ³Έ'μ΄ λ³΄κ΄λλ κ³³μ΄λΌκ³ μκ°ν μ μλ€.
ν΄λμ€ μ λ³΄κ° λ©μλ μμμ λ‘λλ λ, JVMμ μ΄ ν΄λμ€μ λν μ μΌν java.lang.Class
κ°μ²΄λ₯Ό νλ μμ±ν΄μ ν(Heap) μμμ μ μ₯νλ€.
person.getClass()
,Person.class
,Class.forName("Person")
λ±μΌλ‘ μ»λ κ°μ²΄κ° λ°λ‘ μ΄ ν μμμ μλClass
κ°μ²΄μ΄λ€.
-> μ΄Class
κ°μ²΄λ λ©μλ μμμ μ μ₯λ μ€μ λ©νλ°μ΄ν°λ‘ μ κ·Όν μ μλ 리λͺ¨μ»¨ λλ κ²μ΄νΈμ¨μ΄ μν μ νλ€.
μ΄ν 리νλ μ μ½λλ₯Ό μ€ννλ©΄ 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μ μ΄ κ°μ²΄λ€μ΄ κ°μ§ μ 보λ₯Ό μ΄μ©ν΄ λ©μλ μμμ μ€μ μ½λλ
// νμ μλ μ€μ μΈμ€ν΄μ€μ λ©λͺ¨λ¦¬ μ£Όμμ μ κ·Όνμ¬ κ°μ μ‘°μν©λλ€.
리νλ μ
μ κ±°μ λͺ¨λ μμ
μ ν΄λμ€κ° λ‘λλ λ JVMμ΄ ν μμμ μ μ₯νλ java.lang.Class
λΌλ νΉλ³ν κ°μ²΄μμλΆν° μμλλ€. ν΄λΉ κ°μ²΄λ§ μ»μΌλ©΄ ν΄λμ€μ λͺ¨λ μ 보λ₯Ό μΊλΌ μκ° μλ€.
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
μ κ·Ό μ νκΉμ§ μ°ννμ¬ λ΄λΆ μνλ₯Ό μ½κ³ μμ ν μ μλ€.
리νλ μ μ μΌλ°μ μΈ μ ν리μΌμ΄μ μ½λ보λ€λ, νΉμ κΈ°μ μ΄λ κ·μ½μ μμ‘΄νμ§ μλ λ²μ©μ μΈ κΈ°λ₯μ λ§λ€μ΄μΌ νλ νλ μμν¬λ λΌμ΄λΈλ¬λ¦¬μμ ν΅μ¬μ μΈ μν μ νκ² λλ€.
μ€νλ§ νλ μμν¬μ ν΅μ¬μ μΈ κΈ°λ₯μΈ IoC(μ μ΄μ μμ ) 컨ν μ΄λμ DI(μμ‘΄μ± μ£Όμ )λ 리νλ μ κΈ°μ μμ΄λ ꡬνμ΄ λΆκ°λ₯νλ€.
μ€νλ§ μ»¨ν
μ΄λκ° UserService
κ°μ²΄μ UserRepository
λ₯Ό μ£Όμ
(@Autowired
)νλ κ³Όμ μ 리νλ μ
κ΄μ μμ μ΄ν΄λ³΄λ©΄ μλμ κ°λ€.
- μ»΄ν¬λνΈ μ€μΊ: μ ν리μΌμ΄μ μ΄ μμλλ©΄, μ€νλ§μ
@Component
,@Service
,@Repository
κ°μ μ΄λ Έν μ΄μ μ΄ λΆμ ν΄λμ€λ€μ μ°Ύλλ€.
-> μ΄ κ³Όμ μμ ν΄λμ€μ λ©νλ°μ΄ν°λ₯Ό μ½κΈ° μν΄ λ¦¬νλ μ μ΄ μ¬μ©λλ€.
- Bean μΈμ€ν΄μ€ μμ±: μ€νλ§μ μ°ΎμλΈ ν΄λμ€λ₯Ό λ°νμΌλ‘ κ°μ²΄(Bean)λ₯Ό μμ±ν΄μΌ νλ€.
-> μ΄λ 리νλ μ μConstructor.newInstance()
λ₯Ό μ¬μ©νμ¬ κ° ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό λ§λ λ€.
- μμ‘΄μ± μ£Όμ μ€ν:
UserService
Beanμ μμ±ν ν, μ€νλ§μ ν΄λΉ ν΄λμ€λ₯Ό μ€μΊνμ¬@Autowired
μ΄λ Έν μ΄μ μ΄ λΆμ νλ(userRepository
)λ₯Ό μ°Ύλλ€.
- νλ μ 보 λΆμ: 리νλ μ μΌλ‘
userRepository
νλμ νμ μ΄UserRepository
λΌλ κ²μ μμλΈλ€.
- 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μΌλ‘ μ€μ νμ¬λ μμ‘΄μ± μ£Όμ μ μ μμ μΌλ‘ ν΄μ€ μκ° μλ€!
JPA ꡬν체(μ£Όλ‘ νμ΄λ²λ€μ΄νΈ)κ° DBμμ μ‘°νν λ°μ΄ν°λ₯Ό Entity κ°μ²΄λ‘ λ§λλ κ³Όμ μ μλμ κ°λ€.
- λ°μ΄ν° μ‘°ν:
userRepository.findById(1L)
κ°μ λ©μλκ° νΈμΆλλ©΄, νμ΄λ²λ€μ΄νΈλ DBλ‘SELECT * FROM USERS ...
쿼리λ₯Ό λ³΄λ΄ λ°μ΄ν°λ₯Ό μ‘°ννλ€.
- Entity κ°μ²΄ μμ±: μ‘°νλ κ²°κ³Όλ₯Ό λ΄μ Entity κ°μ²΄μ μΈμ€ν΄μ€λ₯Ό λ§λ€μ΄μΌ νλ€. νμ§λ§ νμ΄λ²λ€μ΄νΈλ κ°λ°μκ° μ΄λ€ μμ±μλ₯Ό λ§λ€μ΄ λμμ§ μ ν μ μκ° μλ μνμ΄λ€.
- κΈ°λ³Έ μμ±μ νΈμΆ: κ·Έλμ νμ΄λ²λ€μ΄νΈλ κ°μ₯ μμ νκ³ νμ€ν λ°©λ²μΈ κΈ°λ³Έ μμ±μλ₯Ό 리νλ μ μΌλ‘ νΈμΆνμ¬ 'ν λΉ' κ°μ²΄λ₯Ό λ¨Όμ μμ±νλ€. (
User.class.getConstructor().newInstance()
)
- νλμ κ° λ§€ν: μμ±λ κ°μ²΄μ κ° νλμ 리νλ μ (
Field.set()
)μ μ¬μ©νμ¬ DBμμ κ°μ Έμ¨ κ°μ νλμ© μ±μ λ£λλ€.id
μ»¬λΌ κ°μid
νλμ,name
μ»¬λΌ κ°μname
νλμ μ€μ νλ μμ΄λ€.
JUnitμ΄ @Test
μ΄λ
Έν
μ΄μ
νλλ§ λΆμ΄λ©΄ μμμ ν
μ€νΈλ₯Ό μ€νν΄μ£Όλ κ²λ 리νλ μ
λλΆμ΄λΌ ν μ μλ€.
- ν μ€νΈ λ©μλ κ²μ: JUnit μ€νκΈ°λ μ§μ λ ν μ€νΈ ν΄λμ€(
MyTest.class
)μ λͺ¨λ λ©μλλ₯Ό 리νλ μ μΌλ‘ μ€μΊνλ€.
- μ΄λ Έν μ΄μ νμΈ: μ€μΊν λ©μλλ€ μ€
@Test
μ΄λ Έν μ΄μ μ΄ λΆμ΄μλ λ©μλλ₯Ό μ°Ύμ λͺ©λ‘μΌλ‘ λ§λ λ€. λν@BeforeEach
,@DisplayName
λ± λ€λ₯Έ μ΄λ Έν μ΄μ μ 보λ μ΄λ ν¨κ» μμ§νλ€.
- ν μ€νΈ μ€ν: JUnitμ μ°ΎμλΈ ν μ€νΈ λ©μλ λͺ©λ‘μ μννλ©° 리νλ μ μ
Method.invoke()
λ₯Ό μ¬μ©ν΄ κ° λ©μλλ₯Ό μ€ννλ€.
->Method.invoke()
λ Java Reflection APIμ ν΅μ¬ κΈ°λ₯ μ€ νλλ‘, λ°νμμ νΉμ κ°μ²΄μ λ©μλλ₯Ό λμ μΌλ‘ νΈμΆν μ μκ² ν΄μ£Όλ λ©μλμ΄λ€.
π§π»βπ» μ΄ λλΆμ κ°λ°μκ° ν μ€νΈ λ©μλλ₯Ό μΌμΌμ΄ νΈμΆνλ
main
λ©μλλ₯Ό λ§λ€ νμκ° μμ΄μ§λ€!
리νλ μ κΈ°λ₯μ μ ν리μΌμ΄μ λ¨μμ νμ©ν μΌμ μ μμΌλ, νΉμ λͺ¨λ₯΄λ μ μμ¬νμ λν΄μ μ§κ³ λ§λ¬΄λ¦¬νλ©΄ μ’μ λ―νλ€.
리νλ μ μ ν΅ν λ©μλ νΈμΆμ μΌλ°μ μΈ λ©μλ νΈμΆλ³΄λ€ ν¨μ¬ λλ¦°λ°, JVMμ΄ μ»΄νμΌ μμ μ μ΅μ νλ₯Ό ν μ μμΌλ©° λ°νμμ ν΄λμ€, λ©μλ, νλμ μ 보λ₯Ό νλνλ μ°Ύμλ€λλ κ³Όμ μμ μλΉν μ€λ²ν€λκ° λ°μνκΈ° λλ¬Έμ΄λ€.
λλ¬Έμ κ·Έλ΄ μΌμ μ μκ² μ§λ§, μ±λ₯μ λ―Όκ°ν λ‘μ§μ 리νλ μ APIλ₯Ό ν¬ν¨νλ κ²μ μ§μνλ κ² μ’λ€.
리νλ μ
μ setAccessible(true)
μ΅μ
μ privateμΌλ‘ μ μΈλ νλλ λ©μλμ λν μ κ·Όμ κ°λ₯νκ² νλ―λ‘, κ°μ²΄μ§ν₯ νλ‘κ·Έλλ°μ ν΅μ¬ μμΉ μ€ νλμΈ μΊ‘μνλ₯Ό 무λλ¨λ¦¬κ² λλ€.
κ·Έλ κΈ° λλ¬Έμ νλ μμν¬ λ¨μμμ κ°μ΄ νμμ μΈ μν©μ΄ μλλΌλ©΄ μ¬μ©μ μ§μν΄μΌ νλ€.
리νλ μ μ μ£Όλ‘ λ¬Έμμ΄(String)λ‘ ν΄λμ€λ λ©μλμ μ΄λ¦μ μ§μ νμ¬ μ¬μ©νλ©°, μ΄λ μ»΄νμΌλ¬μ νμ μ²΄ν¬ κΈ°λ₯μ 무λ ₯νμμΌ λ°νμ μλ¬λ₯Ό λ°μμν€λ μμΈμ΄ λλ€.
μ§κΈκΉμ§ Javaμ Reflectionμ λν΄μ μμ보μλ€.
κ·Έλμμλ Spring νλ μμν¬κ° μ΄λ€ μμΌλ‘ Beanμ μμ±νκ³ μ£Όμ
νλμ§ μμ§ λͺ» νλλ°, μ΄λ² κΈ°νλ‘ μ‘°κΈ λ μ΄ν΄ν μ μκ² λμλ κ² κ°λ€.
μμΌλ‘λ λ΄κ° μ¬μ©νλ κΈ°μ λ€μ λμ μ리μ λν΄ μ΄ν΄νλλ‘ λμ± λ Έλ ₯ν΄μΌκ² λ€.
μ°Έκ³ ν λΈλ‘κ·Έ