질문 : Spring @Autowired 필드가 null 인 이유는 무엇입니까?
참고 : 이것은 일반적인 문제에 대한 표준 답변입니다.
@Autowired
필드 ( rateService
)가있는 Spring @Service
클래스 ( MileageFeeCalculator
)가 있지만 사용하려고 할 때 필드가 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; // <--- should be autowired, is null
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile()); // <--- throws NPE
}
}
MileageFeeCalculator
하지만 그렇지 않은 서비스 빈 :
@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)
...
답변
@Autowired
주석이 달린 필드는 new
만든 MileageFeeCalculator의 복사본에 대해 알지 MileageFeeCalculator
하는 것을 null
입니다.
Spring Inversion of Control (IoC) 컨테이너 에는 세 가지 주요 논리적 구성 요소가 있습니다. 애플리케이션에서 사용할 수있는 구성 요소 (빈) ApplicationContext
컨텍스트에서 Bean과의 종속성 및 여러 다른 Bean의 구성을보고 필요한 순서로 인스턴스화 및 구성하는 방법을 결정할 수있는 종속성 솔버.
IoC 컨테이너는 마술이 아니며, 어떻게 든 알려주지 않는 한 Java 객체에 대해 알 수있는 방법이 없습니다. new
를 호출하면 JVM은 새 개체의 복사본을 인스턴스화하여 사용자에게 직접 전달합니다. 구성 프로세스를 거치지 않습니다. Bean을 구성 할 수있는 세 가지 방법이 있습니다.
이 GitHub 프로젝트 에서 Spring Boot를 사용하여이 코드를 모두 게시했습니다. 각 접근 방식에 대해 전체 실행중인 프로젝트를 살펴보고 작동하는 데 필요한 모든 것을 확인할 수 있습니다. NullPointerException
이있는 태그 : 작동 nonworking
가장 바람직한 옵션은 Spring이 모든 bean을 자동 연결하도록하는 것입니다. 이것은 최소한의 코드를 필요로하며 가장 관리하기 쉽습니다. 자동 연결이 원하는대로 작동하도록하려면 다음과 같이 MileageFeeCalculator
@Controller
public class MileageFeeController {
@Autowired
private MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
다른 요청에 대해 서비스 객체의 새 인스턴스를 만들어야하는 경우에도 Spring Bean 범위를 사용하여 주입을 사용할 수 있습니다.
@MileageFeeCalculator
서비스 개체를 삽입하여 작동하는 태그 working-inject-bean
new
로 생성 된 객체가 자동 연결되도록 정말로 필요한 경우 AspectJ 컴파일 타임 위빙과 함께 Spring @Configurable
주석을 사용하여 객체를 주입 할 수 있습니다. 이 접근 방식은 Spring이 새 인스턴스를 구성 할 수 있도록 Spring이 작성 중임을 알리는 코드를 객체의 생성자에 삽입합니다. 이를 위해서는 빌드에서 약간의 구성 (예 : ajc
로 컴파일)하고 Spring의 런타임 구성 핸들러 (JavaConfig 구문으로 @EnableSpringConfigured
이 접근 방식은 Roo Active Record 시스템에서 new
인스턴스가 필요한 지속성 정보를 삽입 할 수 있도록하는 데 사용됩니다.
@Service
@Configurable
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
서비스 개체에서 @Configurable
을 사용하여 작동하는 태그 working-configurable
이 접근 방식은 특별한 상황에서 레거시 코드와의 인터페이스에만 적합합니다. Spring이 autowire 할 수 있고 레거시 코드가 호출 할 수있는 singleton 어댑터 클래스를 만드는 것이 거의 항상 바람직하지만 Spring 애플리케이션 컨텍스트에 빈을 직접 요청할 수도 있습니다.
ApplicationContext
객체에 대한 참조를 제공 할 수있는 클래스가 필요합니다.
@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
출처 : https://stackoverflow.com/questions/19896870/why-is-my-spring-autowired-field-null
'프로그래밍 언어 > Spring MyBatis' 카테고리의 다른 글
Spring Framework의 장점 (0) | 2021.06.28 |
---|---|
SpringData Maven Builds의“수명주기 구성에 포함되지 않는 플러그인 실행”을 해결하는 방법 (0) | 2021.06.26 |
Spring Framework에서 @Inject와 @Autowired의 차이점 (0) | 2021.06.11 |
Spring Boot 애플리케이션 용 포트를 구성하는 방법 (0) | 2021.06.10 |
SpringData JPA에서 CrudRepository와 JpaRepository 인터페이스의 차이점 (0) | 2021.06.10 |