728x90
1. 이슈
Reflection으로 동적 생성한 객체 내 @Autowired된 변수 접근 시 NPE(NullPointerException) 발생
2. 상세 내용
Reflection을 이용하여 객체를 동적으로 생성.
-> method.invoke를 이용하여 객체 내 메서드를 실행
-> InvocationTargetException 발생.
-> 원인을 확인해보니 실행된 메서드 내에서 @Autowired된 변수에 접근 시 NPE 발생
문제가 된 코드
Class targetClass = Class.forName(className);
Object instance = targetClass.getDeclaredConstructor().newInstance();
Method method = targetClass.getDeclaredMethod(methodName, String.class);
method.invoke(instance, 파라미터); // (instance, parameter)
처음에는 InvocationTargetException 발생.
-> 원인을 확인하기 위해 e.getCause()로 원인을 확인하였더니, NullPointerException이 발생된 것을 확인하였음.
[java] java.lang.reflect.InvocationTargetException
...
Caused by: java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
3. 원인
스프링에서 DI는 런타임 시점에 의존성 주입(DI)이 이루어지는데, 위 코드에서 나는 Reflection을 이용해서 인스턴스를 직접 생성(?) 했기 때문에 DI가 되지 않은 객체로, 내부에서 @Autowired된 객체를 사용할 경우 Injection되지 않은채 null이 반환된거였음. 따라서 객체.메서드 를 아무리 해도 null에 접근하였기 때문에 NullPointerException 에러가 발생한 것….
4. 접근
- 구글링했을 때 new로 생성된 객체도 마찬가지로 동일한 이슈가 발생한다는 것을 확인.
- Reflection도 마찬가지로 DI가 되지 않았기 때문에 동일함.
- 동적으로 생성된 객체 내에서 DI된 Bean으로 사용하기 위해서는 applicationContext에서 이미 등록된 Bean을 직접 가져와야 함.
// ApplicationContextServe.java
@Component
public class ApplicationContextServe implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
// NewBeanUtils.java
public class NewBeanUtils {
public static Object getBean(String beanName) {
ApplicationContext context = ApplicationContextServe.getApplicationContet();
return context.getBean(beanName);
}
public static <T> T getBean(Class<T> classType) {
ApplicationContext context = ApplicationContextServe.getApplicationContet();
return context.getBean(classType);
}
}
Class targetClass = Class.forName(className);
Object apiService = NewBeanUtils.getBean(targetClass); // 직접 꺼내씀
Method method = apiService.getClass().getDeclaredMethod(methodName, String.class);
method.invoke(apiService, brodNo);
728x90
'백엔드' 카테고리의 다른 글
[ELK] 2. Kibana에서 Teams WebhookURL로 에러 모니터링하기 (1) | 2023.03.13 |
---|---|
[ELK] 1. Kibana에서 Slack Webhook 모니터링 설정하기 (1) | 2023.03.13 |
[Java] 왜 배열은 Covariant(공변)이고 제네릭은 Invariant(불공변)일까? (0) | 2022.07.22 |
[Java] Covariant Return Type이란? (0) | 2022.07.15 |
[Java] Collection - 2. ArrayList와 Vector (0) | 2022.07.06 |
댓글