Spring @Autowired 필드가 null인 이유는 무엇입니까?
주의: 이것은 일반적인 문제에 대한 정식 답변입니다.
이 있다.@Service
클래스)MileageFeeCalculator
)이 붙어 있습니다.@Autowired
field)rateService
단, 는 ), 「」, 「」.null
용용사에는, 「」, 「」의 양쪽 되어 있습니다.MileageFeeCalculator
과 팥MileageRateService
콩이 만들어지고 있는데, 나는 그 콩이NullPointerException
내가 고 할 mileageCharge
네, 네.봄은 왜 들판에 자동 전력이 공급되지 않는 거죠?
컨트롤러 클래스:
@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
null
봄은 그 때문이다.MileageFeeCalculator
그런 노래입니다.new
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
Spring Inversion of Control(IoC) 컨테이너에는 3개의 주요 논리 컴포넌트(레지스트리라고 함)가 있습니다.ApplicationContext
응용 프로그램에서 사용할 수 있는 컴포넌트(빈), 콘텍스트 내의 빈과 의존관계를 일치시킴으로써 오브젝트의 의존관계를 삽입하는 컨피규레이션시스템 및 많은 다른 빈의 구성을 보고 필요한 경우 또는 필요한 경우 인스턴스화 및 설정방법을 결정할 수 있는 의존관계솔러데르
IoC io io io io io io io 。또한 Java 오브젝트에 대해 알 수 있는 방법이 없습니다.했을 때new
JVM은 새 개체의 복사본을 인스턴스화하여 사용자에게 직접 전달합니다. 구성 프로세스를 거치지 않습니다.콩을 설정하는 방법에는 세 가지가 있습니다.
저는 이 GitHub 프로젝트에서 Spring Boot을 사용하여 이 모든 코드를 올렸습니다.각 접근법에 대해 실행 중인 전체 프로젝트를 보고 작동에 필요한 모든 것을 확인할 수 있습니다.태그 지정:
콩을 주입하다
가장 바람직한 옵션은 스프링이 모든 콩을 자동으로 배선하도록 하는 것입니다. 이는 최소한의 코드만 필요로 하며 가장 유지보수가 용이합니다.을 원하는시키려면 자동 을 해야 .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
서비스 오브젝트:
@Configurable 사용
를 사용하여 new
스프링 주석을 AspectJ 컴파일 시간 위빙과 함께 사용하여 객체를 주입할 수 있습니다.이 접근법은 Spring이 새 인스턴스를 구성할 수 있도록 Spring에게 경고하는 코드를 객체의 생성자에 삽입합니다.이를 위해서는 빌드에 약간의 구성이 필요합니다(예를 들어 컴파일 등).ajc
핸들러스프링)를 @EnableSpringConfigured
Java Config " " " " " " " " 。 시스템에서 되며, " Active Record"를 허용합니다.new
필요한 지속성 정보를 얻기 위한 엔티티의 인스턴스입니다.
@Service
@Configurable
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
를 @Configurable
서비스 오브젝트:
수동 콩 조회: 권장 안 함
이 방법은 특수한 상황에서 레거시 코드와의 인터페이스에만 적합합니다.스프링이 자동 배선할 수 있고 레거시 코드가 호출할 수 있는 싱글톤어댑터 클래스를 작성하는 것은 거의 항상 권장되지만 스프링 애플리케이션 컨텍스트에 직접 빈을 요청할 수 있습니다.
이 봄을 할 수 합니다.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 컨텍스트에서 서비스 개체를 수동으로 검색하여 동작하는 태그:
웹 어플리케이션을 코딩하지 않을 경우 @Autowiring이 실행되는 클래스가 스프링빈인지 확인합니다.일반적으로 봄철 용기는 우리가 봄콩이라고 생각할 수 있는 클래스를 인식하지 못합니다.우리는 스프링 컨테이너에 우리의 봄 수업에 대해 말해야 합니다.
이를 위해서는 appln-contxt로 설정하거나 클래스에 @Component로 주석을 달아 새 연산자를 사용하여 주석을 달지 마십시오.아래 Appln-context에서 확인하시기 바랍니다.
@Component
public class MyDemo {
@Autowired
private MyService myService;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("test");
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
System.out.println("ctx>>"+ctx);
Customer c1=null;
MyDemo myDemo=ctx.getBean(MyDemo.class);
System.out.println(myDemo);
myDemo.callService(ctx);
}
public void callService(ApplicationContext ctx) {
// TODO Auto-generated method stub
System.out.println("---callService---");
System.out.println(myService);
myService.callMydao();
}
}
실제로 메서드를 호출하려면 JVM 관리 개체 또는 스프링 관리 개체를 사용해야 합니다.컨트롤러 클래스의 위의 코드에서 자동 배선 객체를 가진 서비스 클래스를 호출하는 새 개체를 만듭니다.
MileageFeeCalculator calc = new MileageFeeCalculator();
그렇게 되지 않을 거예요.
이 솔루션은 이 MileageFeeCalculator를 컨트롤러 자체의 자동 배선 개체로 만듭니다.
컨트롤러 클래스를 다음과 같이 변경합니다.
@Controller
public class MileageFeeController {
@Autowired
MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
IOC 세계에서의 생활에 익숙하지 않을 때 같은 문제를 겪은 적이 있습니다.그@Autowired
늘이다
은 Spring Spring IoC 컨테이너)에 Spring IoC를 사용하는 것입니다@Autowired
가 올바르게 주입되었습니다.) 는 제로로 field) )) )) )) )) )) ) 。new
이 사람은요즘은@Autowired
스프링이 필드를 주입할 기회가 없기 때문에 필드가 null입니다.
새로운 문제(Java 스타일로 객체 생성)
MileageFeeCalculator calc = new MileageFeeCalculator();
포함 ★★★★★@Service
,@Component
,@Configuration
이
봄.그러나 새 연산자를 사용하여 개체를 만들면 개체가 이미 생성된 애플리케이션 컨텍스트에 등록되지 않습니다.제가사용한 클래스입니다.
이것 좀 봐.
public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String name = "tenant";
System.out.println("Bean factory post processor is initialized");
beanFactory.registerScope("employee", new Employee());
Assert.state(beanFactory instanceof BeanDefinitionRegistry,
"BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used.");
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
if (name.equals(definition.getScope())) {
BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true);
registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
}
}
}
}
봄은 처음이지만, 이 방법을 발견했어요.그것이 바람직하지 않은 방법이라면 가르쳐 주세요.
를 놓다.applicationContext
빈의 : 이콩 :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class SpringUtils {
public static ApplicationContext ctx;
/**
* Make Spring inject the application context
* and save it on a static variable,
* so that it can be accessed from any point in the application.
*/
@Autowired
private void setApplicationContext(ApplicationContext applicationContext) {
ctx = applicationContext;
}
}
원한다면 이 코드를 메인 어플리케이션클래스에 넣을 수도 있습니다.
다른 클래스는 다음과 같이 사용할 수 있습니다.
MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);
이 방법으로 애플리케이션 내의 임의의 오브젝트에 의해 임의의 빈을 얻을 수 있습니다(또한 이 오브젝트에는new
)와 정적인 방법을 사용합니다.
드문 경우처럼 보이지만 제게 일어난 일은 다음과 같습니다.
는 리 we we we we we를 사용했다.@Inject
@Autowired
자바이어느 곳이나 잘 작동했고 콩은 한 군데가 아니라 정확하게 주입되었다.
@Inject
Calculator myCalculator
실제로는 Eclipse auto complete 이 Import한 을 알 수 .com.opensymphony.xwork2.Inject
javax.inject.Inject
!
요약하자면, 주석)을 해 주세요.@Autowired
,@Inject
,@Service
)는 올바른 패키지를 있습니다!, ... ).
여기서 언급되지 않은 것은 이 기사에서 "집행 순서" 단락에 설명되어 있습니다.
클래스에서 @Component 또는 파생상품 @Service 또는 @Repository(더 많은 것 같습니다)를 사용하여 주석을 달아 다른 컴포넌트를 자동 배선해야 한다는 것을 "학습"한 후, 이러한 다른 컴포넌트는 부모 컴포넌트의 컨스트럭터 내에서 여전히 늘이라는 생각이 들었습니다.
@PostConstruct를 사용하면 다음과 같은 문제를 해결할 수 있습니다.
@SpringBootApplication
public class Application {
@Autowired MyComponent comp;
}
또, 다음과 같이 합니다.
@Component
public class MyComponent {
@Autowired ComponentDAO dao;
public MyComponent() {
// dao is null here
}
@PostConstruct
public void init() {
// dao is initialized here
}
}
다음 중 하나가 작동합니다.
@Autowired 를 사용하고 있는 클래스는 Bean 이 아닙니다(new() 를 사용하고 있을 가능성이 있습니다).
SpringConfig 클래스 내에서는 스프링이 @Component를 찾아야 하는 패키지에 대해 언급하지 않았습니다(@ComponentScan(basePackages "여기")).
위의 2개가 동작하지 않으면 System.out.println()을 삽입하여 어디가 잘못되었는지 확인합니다.
테스트 수업 중에 이런 일이 발생할 경우 수업에 주석을 다는 것을 잊지 마십시오.
예를 들어, Spring Boot의 경우:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
....
시간이 좀 지나면...
스프링 부츠는 계속 진화하고 있습니다.더 이상 사용할 필요가 없습니다.@RunWith
올바른 버전의 JUnit을 사용하는 경우.
★★★의 @SpringBootTest
'혼자서 일하세요'를 .@Test
JUnit4가 아닌 JUnit5에서.
//import org.junit.Test; // JUnit4
import org.junit.jupiter.api.Test; // JUnit5
@SpringBootTest
public class MyTests {
....
컴파일되지만, " " " 는 " " 입니다.@Autowired
★★★★★★★★★★★★★★★★★」@Value
를 들어는 "(")"가 .null
스프링 부트는 마법에 의해 동작하기 때문에 이 장애를 직접 디버깅할 수 있는 방법은 거의 없습니다.
다른 은 전화를 거는 SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
MilageFeeCalculator:
@Service
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService; // <--- will be autowired when constructor is called
public MileageFeeCalculator() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
}
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
스프링에 주석을 단 수업을 스캔하도록 지시하는 것을 놓치신 것 같습니다.
하시면 됩니다.@ComponentScan("packageToScan")
스프링 애플리케이션의 구성 클래스에서 스프링 스캔을 지시합니다.
@Service, @Component
기타 주석이 메타 설명을 추가합니다.
스프링은 빈으로 생성되거나 주석으로 표시된 클래스의 인스턴스만 주입합니다.
한 후.@ComponentScan
주석으로 표시된 클래스에 대한 스프링 룩을 지시합니다.이 때@Autowired
관련 빈을 검색하여 필요한 인스턴스를 주입합니다.
주석만 추가하면 종속성 주입이 수정되거나 촉진되지 않습니다. 스프링은 찾아야 할 위치를 알아야 합니다.
, '이유'는 두 수 있습니다.@Autowired
[ ]가 필드null
당신의 클래스는 봄콩이 아닙니다.
밭은 콩이 아닙니다.
업데이트: 매우 똑똑한 사람들은 이 대답을 재빨리 지적했습니다.그 때문에, 이하에 기재되어 있는 이상한 점이 설명되고 있습니다.
원래 답변:
도움이 될지는 모르겠지만, 겉으로 보기에는 옳은 일을 하면서도 같은 문제를 안고 있었습니다.Main 메서드에는 다음과 같은 코드가 있습니다.
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {
"common.xml",
"token.xml",
"pep-config.xml" });
TokenInitializer ti = context.getBean(TokenInitializer.class);
a a a...token.xml
한 줄 파일.
<context:component-scan base-package="package.path"/>
나는 그 소포를 알아차렸다.경로가 더 이상 존재하지 않기 때문에 그냥 선을 끊어버렸습니다.
그 후, NPE가 등장하기 시작했습니다.①의 pep-config.xml
방금 2콩:콩 2개밖에안 먹었어욨다.
<bean id="someAbac" class="com.pep.SomeAbac" init-method="init"/>
<bean id="settings" class="com.pep.Settings"/>
SomeAbac 클래스에는 다음과 같이 선언된 속성이 있습니다.
@Autowired private Settings settings;
알 수 없는 이유로 init에서 설정은 null입니다.<context:component-scan/>
원소는 끝낼 때 이를 basePackage로 일부이다란 거짓말이 존재하지 않는, 모든 게 잘 일한다 없다.요소는 전혀 존재하지않지만 존재하며 기지 Package로 bs가 있으면 모든 것이 잘 작동합니다.이 선 지금 이:이행은 다음과 같습니다처럼 보인다.
<context:component-scan base-package="some.shit"/>
그리고 그것은 동작한다.누군가 설명해 줄 수 있을지도 모르지만, 나에게는 지금으로서는 충분합니다.)
NullPointer이것이 없으면 Null이고 Pointer를 제공하는 원인입니다를 주는 이것은 장본인이다.예외 예외.MileageFeeCalculator calc = new MileageFeeCalculator();
우리는-수동으로 개체를 만들 필요가 없봄을 사용하고 있다.Spring을 사용하고 있으므로 개체를 수동으로 작성할 필요가 없습니다.개체 창조하는 코드 컨테이너로 처리될 것이다.개체 생성은하는 코드의해 처리됩니다 컨테이너에.
또한 서비스 클래스의 @Service 주석을 사용하여 필요한 bean class A를 다른 bean class B 컨스트럭터에 전달하고 @Autowired를 사용하여 클래스 B 컨스트럭터에 주석을 달 수도 있습니다.샘플 스니펫은 다음과 같습니다.
@Service
public class ClassB {
private ClassA classA;
@Autowired
public ClassB(ClassA classA) {
this.classA = classA;
}
public void useClassAObjectHere(){
classA.callMethodOnObjectA();
}
}
또한 만약 어떤 이유에서든 당신은또한 어떤 이유로든,method를 작성하면에 있는 메서드를 만든다 주목하고 있다.@Service
~하듯이로final
, 당신은 그것에서 액세스 할autowired 콩 항상접속하는자동전원 콩은 항상.null
.
이것은 유닛 테스트의 경우에만 유효합니다.
내 서비스 수업이었다내서비스클래스에는서비스 주석이 있었고, 그것은 서비스의 평역이 있었다.@autowired
다른 구성 요소 클래스입니다.다른 컴포넌트 클래슬 때 부품에 수업을 실험했다 오null.테스트했을 때 컴포넌트 클래스는 무효가 되어 있었습니다.왜냐하면 서비스 클래스에서는 다음을 사용하여 개체를 만들고 있었기 때문입니다.new
단위 를 할 , 기입을 하다를 사용하여 있지 합니다.new object()
모크를 주사하다.
이것으로 문제가 해결되었습니다.여기 유용한 링크가 있습니다.
질문과는 전혀 관련이 없지만 필드 주입이 null인 경우에도 생성자 기반 주입은 정상적으로 작동합니다.
private OrderingClient orderingClient;
private Sales2Client sales2Client;
private Settings2Client settings2Client;
@Autowired
public BrinkWebTool(OrderingClient orderingClient, Sales2Client sales2Client, Settings2Client settings2Client) {
this.orderingClient = orderingClient;
this.sales2Client = sales2Client;
this.settings2Client = settings2Client;
}
또, 입, 입, 에, a, 。static
가 ''''가 됩니다'''null
.
를 private
방음음음음 method method method method method method method method method method method 가 됩니다.null
바꿔보세요.private
로로 합니다.public
컨트롤러에 있습니다.
언급URL : https://stackoverflow.com/questions/19896870/why-is-my-spring-autowired-field-null
'programing' 카테고리의 다른 글
Vuex 모듈에서 상속하는 방법 (0) | 2022.08.08 |
---|---|
Vue 및 Vuex가 html에서 적절한 값을 취득하지 않음 (0) | 2022.08.08 |
vuejs 필터에 인수를 전달하는 방법 (0) | 2022.08.08 |
C99의 가장 유용한 신기능은 무엇입니까? (0) | 2022.08.08 |
Java에서 어레이의 일부만 가져오시겠습니까? (0) | 2022.08.08 |