注意:这是一个常见问题的规范答案。
我有一个Spring @Service类(MileageFeeCalculator),它有一个@Autowired字段(rateService),但当我尝试使用它时,该字段为空。日志显示正在创建MileageFeeCalculator bean和MileageRateService bean,但是每当我试图在服务bean上调用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
}
}
服务bean,应该在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)
...
更新:真正聪明的人很快就指出了这个答案,这解释了下面描述的奇怪之处
最初的回答:
我不知道这是否对任何人都有帮助,但我被同样的问题困住了,即使我做的事情看起来是正确的。在Main方法中,我有如下代码:
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {
"common.xml",
"token.xml",
"pep-config.xml" });
TokenInitializer ti = context.getBean(TokenInitializer.class);
在token。xml文件中有一行
<context:component-scan base-package="package.path"/>
我注意到这个包装。路径已经不存在了,所以我干脆把这行删掉了。
在那之后,NPE开始进入。在pep-config.xml中,我只有2个bean:
<bean id="someAbac" class="com.pep.SomeAbac" init-method="init"/>
<bean id="settings" class="com.pep.Settings"/>
SomeAbac类有一个属性声明为
@Autowired private Settings settings;
由于一些未知的原因,init()中的settings为空,当<context:component-scan/>元素根本不存在时,但是当它存在并且有一些bs作为basePackage时,一切都能正常工作。这条线现在看起来是这样的:
<context:component-scan base-package="some.shit"/>
这很有效。也许有人可以提供一个解释,但对我来说,现在已经足够了)
你的问题是新的(java风格的对象创建)
MileageFeeCalculator calc = new MileageFeeCalculator();
使用注释@Service、@Component、@Configuration bean在
当服务器启动时,Spring的应用程序上下文。但是当我们创建对象时
使用new操作符,对象不会在已经创建的应用程序上下文中注册。例如Employee.java类,我使用过。
看看这个:
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());
}
}
}
}