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

 

Trail: The Reflection API (The Java™ Tutorials)

Uses of Reflection Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers

docs.oracle.com

 

+ Recent posts