Reflection
- Java에서 지원하는 API로, 객체를 통해 클래스의 정보를 분석해 낼 수 있다.
- 즉, 실행중인 Java Application의 Class 정보를 동적으로 접근하여 메소드, 필드 등에 접근하거나 인스턴스를 다룬다.
- 대표적인 예로 Spring의 Bean들은 Reflection을 통해 인스턴스들이 다뤄진다.
실제로 org.springframework.beans.annotation.AnnotationBeanUtils 클래스 내부를 보면 bean의 properties를 copy하는 메소드를 찾을 수 있는데, Object 타입의 bean과 java.lang.reflection.Method를 통해 bean의 메소드들이 다뤄지는 것을 확인할 수 있다.
/**
* Copy the properties of the supplied {@link Annotation} to the supplied target bean.
* Any properties defined in {@code excludedProperties} will not be copied.
* <p>A specified value resolver may resolve placeholders in property values, for example.
* @param ann the annotation to copy from
* @param bean the bean instance to copy to
* @param valueResolver a resolve to post-process String property values (may be {@code null})
* @param excludedProperties the names of excluded properties, if any
* @see org.springframework.beans.BeanWrapper
*/
public static void copyPropertiesToBean(Annotation ann, Object bean, @Nullable StringValueResolver valueResolver,
String... excludedProperties) {
Set<String> excluded = new HashSet<>(Arrays.asList(excludedProperties));
Method[] annotationProperties = ann.annotationType().getDeclaredMethods();
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(bean);
for (Method annotationProperty : annotationProperties) {
String propertyName = annotationProperty.getName();
if (!excluded.contains(propertyName) && bw.isWritableProperty(propertyName)) {
Object value = ReflectionUtils.invokeMethod(annotationProperty, ann);
if (valueResolver != null && value instanceof String) {
value = valueResolver.resolveStringValue((String) value);
}
bw.setPropertyValue(propertyName, value);
}
}
}
샘플 예제
간단하게 샘플 예제를 구현해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Calculator {
private String name;
public Calculator() {
System.out.println("call Calculator()");
}
public int add(int a, int b) {
System.out.println("call add()");
int result = a + b;
return result;
}
public int minus(int a, int b) {
System.out.println("call minus()");
int result = a - b;
return result;
}
}
public class ReflectionTest {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("Calculator");
Field[] fields = cls.getDeclaredFields();
for(Field field: fields) {
System.out.println("field="+field.getName());
}
Calculator calculator = new Calculator();
Method[] methods = cls.getDeclaredMethods();
for(Method method: methods) {
Object s = method.invoke(calculator, 4,3);
System.out.println("result=" + s);
}
System.out.println("Class="+cls.getName());
}
}
|
cs |
field=name
call Calculator()
call add()
result=7
call minus()
result=1
Class=Calculator
장점
확장: 확장 가능한 인스턴스를 만들어 외부 사용자 정의 클래스를 작성 할 수 있다.
디버깅 및 테스트: 디버거는 리플렉션 속성을 사용하여 클래스의 private memeber를 체크할 수 있다.
단점
성능 : reflection은 성능이 느리므로 성능에 민감한 프로그램이라면, 자주 호출되는 코드에서는 피하는 것이 좋다.
내부 노출 : reflection은 클래스 추상화를 손상 시킬 수 있다. 즉, 클래스 코드의 변경이 있으면 동작의 변경이 따를 수 있다.
https://docs.oracle.com/javase/tutorial/reflect/index.html
'programming > Java' 카테고리의 다른 글
primitive type과 boxed primitives (0) | 2019.11.24 |
---|---|
[JAVA 8] - Default Method, Functional Interface (Prediceate, Consumer, ...) (0) | 2019.02.17 |
[JAVA 8] - 함수형 프로그래밍(Functional Programming) (0) | 2019.02.17 |
# Enum (열거형) (0) | 2018.05.20 |
# NIO - Selector (0) | 2018.05.19 |