π μ΄ κΈμ μΈνλ°μμ μ 곡νλ "μ€νλ§ ν΅μ¬ μ리 - κ³ κΈνΈ" κ°μλ₯Ό μκ°νλ©΄μ μ 리ν λ΄μ©μ λ°νμΌλ‘ μμ±ν κΈμ λλ€.
μ΄μ κΈ μμ νλ‘μλ₯Ό μ¬μ©ν΄μ κΈ°μ‘΄ μ½λλ₯Ό λ³κ²½νμ§ μκ³ λΆκ°κΈ°λ₯μ μ μ©νλ λ°©λ²μ μμλ΄€λ€. κ·Έλ¬λ ν΄λμ€ κΈ°λ° νλ‘μμ κ²½μ° λΆκ°κΈ°λ₯μ μ μ©ν΄μΌ νλ λμ ν΄λμ€κ° 100κ°λΌλ©΄ νλ‘μ ν΄λμ€λ 100κ° λ§λ€μ΄μΌ νλ€. νλ‘μ ν΄λμ€λ₯Ό νλλ§ λ§λ€μ΄μ λͺ¨λ κ³³μ μ μ©ν μλ μμκΉ ?
μλ°κ° κΈ°λ³ΈμΌλ‘ μ 곡νλ JDK λμ νλ‘μ κΈ°μ μ νμ©νλ©΄ νλ‘μ κ°μ²΄λ₯Ό λμ μΌλ‘ λ§λ€μ΄λΌ μ μλ€.
JDK λμ νλ‘μλ₯Ό μ΄ν΄νκΈ° μν΄μλ λ¨Όμ μλ°μ 리νλ μ κΈ°μ μ μ΄ν΄ν΄μΌ νλ€.
⻠리νλ μ κΈ°μ
- 리νλ μ κΈ°μ μ ν΅ν΄ ν΄λμ€λ λ©μλμ λ©νμ 보λ₯Ό λμ μΌλ‘ νλν μ μλ€
- 리νλ μ κΈ°μ μ ν΅ν΄ μ½λλ₯Ό λμ μΌλ‘ νΈμΆν μ μλ€
λ¨Όμ μλ μ½λλ₯Ό 보μ
@Test
void reflection0() {
Hello target = new Hello();
//κ³΅ν΅ λ‘μ§1 μμ
log.info("start");
String result1 = target.callA(); //νΈμΆνλ λ©μλκ° λ€μ
log.info("result={}", result1);
//κ³΅ν΅ λ‘μ§1 μ’
λ£
//κ³΅ν΅ λ‘μ§2 μμ
log.info("start");
String result2 = target.callB(); //νΈμΆνλ λ©μλκ° λ€μ
log.info("result={}", result2);
//κ³΅ν΅ λ‘μ§2 μ’
λ£
}
곡ν΅λ‘μ§ 1κ³Ό 2λ νΈμΆνλ λ©μλλ§ λ€λ₯΄κ³ μ 체 μ½λ νλ¦μ΄ μμ κ°λ€.
μ¬κΈ°μ κ³΅ν΅ λ‘μ§ 1κ³Ό 2λ₯Ό νλμ λ©μλλ‘ λ½μμ ν©μΉκ³ μΆλ€.
μ€κ°μ νΈμΆνλ λ©μλκ° λ€λ₯΄κΈ°λλ¬Έμ μ¬μ 보μ΄μ§λ§ λ©μλλ‘ λ½μμ 곡ν΅ννλ κ²μ΄ μ΄λ ΅λ€.
μ΄λ μ¬μ©νλ κΈ°μ μ΄ λ¦¬νλ μ μ΄λ€.
리νλ μ μ ν΄λμ€λ λ©μλμ λ©νμ 보λ₯Ό μ¬μ©ν΄μ λμ μΌλ‘ νΈμΆνλ λ©μλλ₯Ό λ³κ²½ν μ μλ€.
@Test
void reflection1() throws Exception {
//ν΄λμ€ μ 보
Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");
Hello target = new Hello();
//callA λ©μλ μ 보
Method methodCallA = classHello.getMethod("callA");
Object result1 = methodCallA.invoke(target);
log.info("result1={}", result1);
//callB λ©μλ μ 보
Method methodCallB = classHello.getMethod("callB");
Object result2 = methodCallB.invoke(target);
log.info("result2={}", result2);
}
- Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");
- Class.forName(...) μ ν΄λμ€ μ΄λ¦μ λ¬Έμμ΄λ‘ λ°μμ ν΄λμ€λ₯Ό JVM μ λ‘λ©νκ³ ν΄λμ€μ λ©νμ 보λ₯Ό λ°ννλ μν μ νλ€.
- () μμλ ν¨ν€μ§λͺ λΆν° λ΄λΆ ν΄λμ€κΉμ§ ν¬ν¨ν "μμ ν ν΄λμ€ μ΄λ¦" μ΄ λ€μ΄κ°λ€.
- λ©νμ 보μ ν¬ν¨λ λ΄μ©μ ν΄λμ€μ΄λ¦, νλ μ 보, λ©μλ μ 보, μμ±μμ 보, μμν΄λμ€ λ±μ΄ μλ€.
classHello.getMethod("A") λ₯Ό ν΅ν΄ λ©μλ λ©νμ 보λ₯Ό νλν λ€, methodCallA μ ν λΉνλ€.
methodCallA.invoke(μΈμ€ν΄μ€) λ μ§μ ν μΈμ€ν΄μ€(target)μ λ©μλ(A)λ₯Ό μ€νΌν μ μκ² νλ€.
μ΄λ κ² νλ©΄ λ©μλ μ 보λ₯Ό λμ μΌλ‘ λ³κ²½ν μ μκ² λλ€.
λ©μλ νΈμΆ λΆλΆ 곡ν΅λ‘μ§μΌλ‘ λΆλ¦¬ν΄λ΄κΈ°
@Test
void reflection2() throws Exception {
//ν΄λμ€ μ 보
Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");
Hello target = new Hello();
Method methodCallA = classHello.getMethod("callA");
dynamicCall(methodCallA, target);
Method methodCallB = classHello.getMethod("callB");
dynamicCall(methodCallB, target);
}
private void dynamicCall(Method method, Object target) throws Exception {
log.info("start");
Object result = method.invoke(target);
log.info("result={}", result);
}
- dynamicCall(Method method, Object target)
- 곡ν΅λ‘μ§ 1,2 λ₯Ό νλ²μ μ²λ¦¬ν μ μλ ν΅ν©λ κ³΅ν΅ μ²λ¦¬ λ‘μ§μ΄λ€.
- Method method : 첫λ²μ§Έ νλΌλ―Έν°λ νΈμΆν λ©μλ μ λ³΄κ° λμ΄μ¨λ€. κΈ°μ‘΄μλ λ©μλ μ΄λ¦μ μ§μ νΈμΆνμ§λ§ μ΄μ λ Method λ©νμ 보λ₯Ό ν΅ν΄μ νΈμΆν λ©μλ μ λ³΄κ° λμ μΌλ‘ μ 곡λλ€.
- Object target : μ€μ μ€νν μΈμ€ν΄μ€ μ λ³΄κ° λμ΄μ¨λ€. νμ μ΄ Object μ΄κΈ° λλ¬Έμ μ΄λ ν μΈμ€ν΄μ€λ λ°μ μ μλ€.
- μ£Όμ ! λΉνν method.invode(target) μ μ¬μ©ν λ νΈμΆν ν΄λμ€μ λ©μλ μ λ³΄κ° λ€λ₯΄λ©΄ μμΈκ° λ°μνλ€.
Q. λ©μλ νΈμΆ λΆλΆλ§ λ€λ₯Έ κ³΅ν΅ λ‘μ§μ΄ μμλ, μ΄λ₯Ό κ°μ νλ λ°©λ²μ 무μμ΄ μμκΉμ ?
βΆ A. λ©μλ νΈμΆ λΆλΆλ§ λ€λ₯Έ κ³΅ν΅ λ‘μ§μ΄ μλ€λ©΄, 리νλ μ κΈ°μ μ νμ©ν΄ Method λΌλ λ©νμ 보 κ°μ²΄λ‘ μΆμννμ¬ κ³΅ν΅ λ‘μ§μ νλλ‘ ν΅ν©ν μ μμ΅λλ€. 리νλ μ μ μ¬μ©νλ©΄, νΈμΆν λ©μλλ₯Ό λ¬Έμμ΄λ‘ μ§μ νμ¬ Method κ°μ²΄λ‘ μ»κ³ , μ΄λ₯Ό ν΅ν΄ μ€μ μΈμ€ν΄μ€μ λν΄ λμ μΌλ‘ λ©μλλ₯Ό μ€νν μ μμ΅λλ€. μ΄μ κ°μ΄ 리νλ μ μ μ¬μ©νλ©΄ ν΄λμ€μ λ©μλμ λ©ν μ 보λ₯Ό μ¬μ©ν΄μ μ ν리μΌμ΄μ μ λμ μΌλ‘ μ μ°νκ² λ§λ€ μ μμ§λ§, 리νλ μ κΈ°μ μ λ°νμμ λμνκΈ° λλ¬Έμ μ»΄νμΌ μμ μ μ€λ₯λ₯Ό μ‘μ μ μμ΅λλ€. κ·Έλμ μΌλ°μ μΌλ‘λ κΆμ₯λμ§ μμ΅λλ€.
β» JDK λμ νλ‘μ
JDK λμ νλ‘μλ₯Ό μκΈ° μν΄ λ¨Όμ 리νλ μ μ μμλ΄€λ€.
μμμλ κ°λ°μκ° μ§μ νλ‘μ ν΄λμ€λ₯Ό λ§λ€μ΄ λ¬Έμ λ₯Ό ν΄κ²°νμλ€ (νλ‘μ ν¨ν΄, λ°μ½λ μ΄ν° ν¨ν΄)
λμ νλ‘μ κΈ°μ μ μ¬μ©νλ©΄ κ°λ°μκ° μ§μ νλ‘μ ν΄λμ€λ₯Ό λ§λ€μ§ μμλ λλ€(JVM μ΄ νλ‘μ ν΄λμ€λ₯Ό λ°νμμ λμ μΌλ‘ μμ±ν΄μ£ΌκΈ° λλ¬Έ) λμ νλ‘μ κΈ°μ μ νλ‘μ κ°μ²΄λ₯Ό λμ μΌλ‘ λ°νμμ κ°λ°μ λμ λ§λ€μ΄μ€λ€. κ°λ°μλ λμ νλ‘μμ μνλ μ€ν λ‘μ§μ μ§μ ν μ μλ€. JDK λμ νλ‘μλ μΈν°νμ΄μ€λ₯Ό κΈ°λ°μΌλ‘ νλ‘μλ₯Ό λμ μΌλ‘ λ§λ€μ΄μ€λ€. λ°λΌμ μΈν°νμ΄μ€κ° νμμ΄λ€.
βΆ λμ νλ‘μμ ꡬμ±
public interface AInterface {
String call();
}
public class AImpl implements AInterface {
@Override
public String call() {
log.info("A νΈμΆ");
return "a";
}
}
public interface BInterface {
String call();
}
public class BImpl implements BInterface {
@Override
public String call() {
log.info("B νΈμΆ");
return "b";
}
}
βοΈβοΈβοΈ JDK λμ νλ‘μμ μ μ©ν λ‘μ§μ λ°λμ InvocationHandler μΈν°νμ΄μ€λ₯Ό ꡬνν΄μ μ 곡ν΄μΌ νλ€ βοΈβοΈβοΈ
νΈλ€λ¬λ μ΄ μΈν°νμ΄μ€λ₯Ό ꡬνν κ°μ²΄μ¬μΌλ§ νλ‘μκ° λμν μ μλ€. νλ‘μκ° κ°λ‘μ± λ©μλ λ‘μ§μ invoke() λ΄λΆμ μ μν΄μΌνκΈ° λλ¬Έμ΄λ€(invoke()λ InvocationHandlerμ ꡬν λ©μλμ)
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
- InvocationHandler λ JDK λμ νλ‘μμμ λ©μλ νΈμΆμ κ°λ‘μ±λ νΈλ€λ¬ μΈν°νμ΄μ€λ‘, νλ‘μ κ°μ²΄μ λ©μλκ° νΈμΆλ λ μ€μ ꡬν체 λμ μ΄ νΈλ€λ¬μ invoke() λ©μλκ° μ€νλ¨
- proxy : νλ‘μ κ°μ²΄ μμ
- method : νΈμΆλ λ©μλ(λ©νμ 보)
- args : μ λ¬λ μΈμ
- 리ν΄κ° : μλ λ©μλμ μ€νκ²°κ³Ό
InvocationHandler λ₯Ό ꡬνν TimeInvocationHandler
public class TimeInvocationHandler implements InvocationHandler {
private final Object target;
public TimeInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("TimeProxy μ€ν");
long startTime = System.currentTimeMillis();
Object result = method.invoke(target, args);
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("TimeProxy μ’
λ£ resultTime={}", resultTime);
return result;
}
}
- Object result = method.invoke(target, args) : target μΈμ€ν΄μ€μ method λ₯Ό μ€νν΄(invoke) !!! λΌλ λ»
βΆ λμ νλ‘μμ μ¬μ©
public class JdkDynamicProxyTest {
@Test
void dynamicA() {
AInterface target = new AImpl();
TimeInvocationHandler handler = new TimeInvocationHandler(target);
AInterface proxy = (AInterface) Proxy.newProxyInstance(AInterface.class.getClassLoader(), new Class[]{AInterface.class}, handler);
proxy.call();
log.info("targetClass={}", target.getClass());
log.info("proxyClass={}", proxy.getClass());
}
@Test
void dynamicB() {
BInterface target = new BImpl();
TimeInvocationHandler handler = new TimeInvocationHandler(target);
BInterface proxy = (BInterface) Proxy.newProxyInstance(BInterface.class.getClassLoader(), new Class[]{BInterface.class}, handler);
proxy.call();
log.info("targetClass={}", target.getClass());
log.info("proxyClass={}", proxy.getClass());
}
}
μ μ½λμμ JDK λμ νλ‘μλ₯Ό μμ±νλ ν΅μ¬μ½λ
AInterface proxy = (AInterface) Proxy.newProxyInstance(
AInterface.class.getClassLoader(), // β ν΄λμ€ λ‘λ
new Class[]{AInterface.class}, // β‘ νλ‘μκ° κ΅¬νν μΈν°νμ΄μ€ λͺ©λ‘
handler // β’ λ©μλ νΈμΆμ κ°λ‘μ± InvocationHandler ꡬν체
);
- β ν΄λμ€ λ‘λ : νλ‘μ κ°μ²΄λ JVM μμμ Class λ‘ μμ±λλ―λ‘, JVM μ΄ λ‘λ©ν λ ν΄λμ€ λ‘λκ° νμνλ°, μ΄λ₯Ό λ겨μ€
- β‘ νλ‘μκ° κ΅¬νν μΈν°νμ΄μ€ λͺ©λ‘ : λμ νλ‘μλ μΈν°νμ΄μ€ κΈ°λ°μ΄λ―λ‘, μ¬κΈ°μ μ΄λ€ μΈν°νμ΄μ€λ₯Ό ꡬνν΄μΌν μ§λ₯Ό λͺ μν΄μ€
- β’ λ©μλ νΈμΆμ κ°λ‘μ± InvocationHandler ꡬν체 : λͺ¨λ λ©μλ νΈμΆμ μ΄ handler.invoke(proxy, method, args) λ‘ μμλ¨
μ΄λ κ² μμ±λ AInterface proxy λ AInterface λ₯Ό ꡬννκ³ μμΌλ©°,
proxy.call() λ©μλ νΈμΆ μ μ§μ AImpl μ νΈμΆνλ κ²μ΄ μλλΌ TimeInvocationHandler.invoke() λ΄λΆλ‘ νλ¦μ΄ μ λ¬λ¨
μ€νμμ
- 1. ν΄λΌμ΄μΈνΈλ JDK λμ νλ‘μμ call()μ μ€ννλ€
- 2. JDK λμ νλ‘μλ InvocationHandler.invoke() λ₯Ό νΈμΆνλ€. TimeInvocationHandler κ° κ΅¬νμ²΄λ‘ μμΌλ―λ‘ TimeInvocationHandler.invoke() κ° νΈμΆλλ€.
- 3. TimeInvocationHandler κ° λ΄λΆ λ‘μ§μ μννκ³ , method.invoke(target, args) λ₯Ό νΈμΆν΄μ targetμΈ μ€μ κ°μ²΄(AImpl) λ₯Ό νΈμΆνλ€.
- 4. AImpl μΈμ€ν΄μ€μ call()μ΄ μ€νλλ€.
- 5. AImpl μΈμ€ν΄μ€μ call()μ μ€νμ΄ λλλ©΄ TimeInvocationHandler λ‘ μλ΅μ΄ λμμ¨λ€. μκ°λ‘κ·Έλ₯Ό μΆλ ₯νκ³ κ²°κ³Όλ₯Ό λ°ννλ€.
Q. λ©μλ νΈμΆ λΆλΆλ§ λ€λ₯Έ κ³΅ν΅ λ‘μ§μ΄ μμλ, μ΄λ₯Ό κ°μ νλ λ°©λ²μ 무μμ΄ μμκΉμ ?
βΆ A . λ©μλ νΈμΆ λΆλΆλ§ λ€λ₯Έ κ³΅ν΅ λ‘μ§μ΄ λ°λ³΅λλ€λ©΄, JDK λμ νλ‘μλ₯Ό νμ©ν΄ κ³΅ν΅ λ‘μ§μ νλμ νΈλ€λ¬λ‘ μΆμνν μ μμ΅λλ€.
λ§μ½ μ μ© λμμ΄ 100κ°μ¬λ λμ νλ‘μλ₯Ό ν΅ν΄μ μμ±νκ³ κ°κ° νμν InvocationHandler λ§ λ§λ€μ΄μ λ£μ΄μ£Όλ©΄ λ©λλ€.
JDK μ λμ νλ‘μ κΈ°λ₯μ΄ λ°νμμ νλ‘μ κ°μ²΄λ₯Ό μλμΌλ‘ μμ±ν΄μ£ΌκΈ° λλ¬Έμ, κ°λ°μλ κ³΅ν΅ λ‘μ§λ§ ν κ³³μ μμ±νλ©΄ λκ³ , μ€μ λ©μλ νΈμΆμ λμ μΌλ‘ μμμ΄ λ©λλ€.
μ¬κΈ°κΉμ§ νλ‘μ κ°μ²΄κ° λ©μλλ₯Ό κ°λ‘μ±κ³ , νΈλ€λ¬μμ κ³΅ν΅ λ‘μ§μ μνν λ€ μ€μ λ©μλλ₯Ό νΈμΆνλ ꡬ쑰λ₯Ό κ²½ννλλ°,
μ€νλ§ AOP μμ μ΄λ¬ν ꡬ쑰(νλ‘μ κΈ°λ° + λ©μλ μμ)λ₯Ό λ°νμΌλ‘ ν΅μ¬ λΉμ¦λμ€ λ‘μ§κ³Ό κ³΅ν΅ κ΄μ¬μ¬(μ: νΈλμμ , λ‘κΉ , 보μ λ±)λ₯Ό λΆλ¦¬νλ€.