반응형
Notice
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
Tags
- 데이터구조
- Yes
- 머신러닝
- 컴퓨터과학
- 자바스크립트
- 클라우드컴퓨팅
- 보안
- 버전관리
- 프로그래밍언어
- 파이썬
- 사이버보안
- 딥러닝
- 컴퓨터공학
- springboot
- 데이터베이스
- 빅데이터
- 소프트웨어
- 프로그래밍
- 알고리즘
- 웹개발
- 데이터과학
- 디자인패턴
- 소프트웨어공학
- 인공지능
- 네트워크
- I'm Sorry
- 컴퓨터비전
- 네트워크보안
- 데이터분석
- 자료구조
Archives
- Today
- Total
스택큐힙리스트
왜 내 Spring @Autowired 필드가 null인가요? 본문
반응형
참고: 이것은 일반적인 문제에 대한 권위 있는 답변을 제공하기 위한 것입니다.
저는 @Service 클래스 (MileageFeeCalculator)에 @Autowired 필드 (rateService)가 있는데, 이 필드를 사용하려고 할 때 null이 됩니다. 로그는 MileageFeeCalculator 빈과 MileageRateService 빈이 모두 생성되었음을 보여줍니다. 그렇지만 서비스 빈의 mileageCharge 메소드를 호출하려고 할 때마다 NullPointerException이 발생합니다. 왜 Spring이 필드를 자동 주입하지 않을까요?
컨트롤러 클래스:
@Controller
public class MileageFeeController {
@RequestMapping(/mileage/{miles})
@ResponseBody
public float mileageFee(@PathVariable int miles) {
MileageFeeCalculator calc = new MileageFeeCalculator();
return calc.mileageCharge(miles);
}
}
서비스 클래스:
@Service
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService; // <--- autowired로 지정되어야 하지만 null 값인 상태입니다.
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile()); // <--- NPE를 발생시킵니다.
}
}
MileageFeeCalculator에서 autowired 되어야 하는 Service 빈이지만, 그렇지 않습니다:
@Service
public class MileageRateService {
public float ratePerMile() {
return 0.565f;
}
}
GET /mileage/3을 시도할 때, 다음과 같은 예외가 발생합니다:
java.lang.NullPointerException: null
at com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13)
at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14)
...
답변 1
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
}
그럼 기존의 코드에서 getContext()를 호출하고 필요한 빈을 얻을 수 있습니다:
@Controller
public class MileageFeeController {
@RequestMapping(/mileage/{miles})
@ResponseBody
public float mileageFee(@PathVariable int miles) {
MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
return calc.mileageCharge(miles);
}
}
Spring 컨텍스트에서 서비스 개체를 수동으로 찾아 작동하는 태그: working-manual-lookup
답변 2
스프링의 @Autowired 필드가 null인 이유는 무엇일까요?스프링 프레임워크는 개발자들에게 편리한 의존성 주입(Dependency Injection) 기능을 제공하는데, @Autowired 어노테이션은 자동으로 필요한 객체를 주입해주는 역할을 합니다. 하지만 때때로 개발자들은 @Autowired 필드가 예상대로 주입되지 않고 null 값을 가지는 경우를 마주할 수 있습니다. 이러한 문제의 원인과 해결 방법에 대해 알아보겠습니다.
첫째, 스프링 컨테이너에서 빈으로 등록되지 않은 클래스는 @Autowired 어노테이션을 이용한 주입이 이뤄지지 않습니다. 스프링은 컨테이너에 등록된 빈들만을 자동으로 주입할 수 있기 때문에, 해당 클래스가 스프링 빈으로 등록되어 있는지 확인해야 합니다. 클래스에 @Component, @Service, @Repository 등의 어노테이션을 추가하여 스프링 빈으로 등록해야 주입이 이뤄집니다.
둘째, @Autowired 필드를 사용하는 클래스 역시 스프링 빈으로 등록되어야 합니다. 스프링은 빈으로 등록된 클래스들 사이에서만 의존성 주입을 수행할 수 있습니다. 따라서 @Autowired 필드를 사용하는 클래스에도 @Component, @Service, @Repository 등의 어노테이션을 추가해서 스프링 빈으로 등록해야 합니다.
셋째, @Autowired 어노테이션을 적용하는 위치에 따라 주입이 이뤄지지 않을 수 있습니다. @Autowired 어노테이션을 필드에 직접 추가하는 것 외에도 생성자, 메소드 매개변수, 메소드에 어노테이션을 사용할 수 있습니다. 주입이 이뤄지지 않는다면 어노테이션을 다른 곳에 추가해 보거나, @Autowired(optional = true)와 같이 옵션을 설정해 주는 것도 고려해 볼 수 있습니다.
넷째, 스프링 설정 파일에 컴포넌트 스캔이 제대로 설정되지 않아서 주입이 이뤄지지 않을 수 있습니다. 스프링 설정 파일에
마지막으로, 스프링 라이프사이클 이슈로 인해 주입이 지연될 수 있습니다. 스프링의 빈 라이프사이클은 초기화 과정을 거치기 때문에, 주입이 이뤄지기 전에 해당 필드가 참조되어 null 값이 되는 경우가 있을 수 있습니다. 이럴 때는 @PostConstruct 어노테이션을 메소드에 추가하여 주입이 완료된 후 실행되는 메소드로 이슈를 해결할 수 있습니다.
@Autowired 필드가 null 값을 가질 때, 위의 다섯 가지 이유를 확인해 볼 필요가 있습니다. 클래스 빈 등록, 컴포넌트 스캔 설정, 어노테이션 적용 위치 등을 확인하고 조치함으로써 @Autowired 필드가 null인 문제를 해결할 수 있습니다. 따라서 스프링 어플리케이션을 개발하면서 주입이 null인 경우가 발생할 때에는 위의 이유들을 체크하여 해결하는 것이 중요합니다.
반응형
Comments