为什么我的 Spring @Autowired 字段为 null?
为什么我的 Spring @Autowired 字段为 null?
技术背景
在Spring应用开发中,@Autowired
注解是实现依赖注入的常用方式,它可以自动将所需的Bean注入到相应的字段中。然而,有时候会遇到使用 @Autowired
注解的字段为 null
的情况,这会导致 NullPointerException
异常,影响程序的正常运行。
实现步骤
1. 检查对象创建方式
Spring IoC容器负责管理Bean的生命周期和依赖注入。如果使用 new
关键字手动创建对象,Spring无法对其进行配置和注入依赖。
错误示例:
@Controller
public class MileageFeeController {
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
MileageFeeCalculator calc = new MileageFeeCalculator(); // 手动创建对象
return calc.mileageCharge(miles);
}
}
正确示例:使用 @Autowired
注解让Spring自动注入对象。
@Controller
public class MileageFeeController {
@Autowired
private MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
2. 确保类是Spring Bean
要让Spring对类进行管理和依赖注入,类必须是Spring Bean。可以使用 @Component
、@Service
、@Repository
、@Controller
等注解将类标记为Spring Bean。
@Service
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
3. 配置组件扫描
确保Spring能够扫描到标记为Bean的类。可以使用 @ComponentScan
注解指定要扫描的包。
@Configuration
@ComponentScan(basePackages = "com.chrylis.example")
public class AppConfig {
// 配置类
}
4. 检查注解导入的包
确保使用的注解(如 @Autowired
、@Inject
、@Service
等)导入的是正确的包。
import org.springframework.beans.factory.annotation.Autowired; // 正确的导入
5. 避免在构造函数中使用未初始化的依赖
在构造函数中,@Autowired
注解的字段可能还未初始化。可以使用 @PostConstruct
注解在Bean初始化后执行一些操作。
@Component
public class MyComponent {
@Autowired
ComponentDAO dao;
public MyComponent() {
// dao 在这里为 null
}
@PostConstruct
public void init() {
// dao 在这里已初始化
}
}
核心代码
示例代码结构
-
MileageFeeController
:控制器类,处理HTTP请求。 -
MileageFeeCalculator
:服务类,计算里程费用。 -
MileageRateService
:服务类,提供每英里的费率。
// MileageFeeController.java
@Controller
public class MileageFeeController {
@Autowired
private MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
// MileageFeeCalculator.java
@Service
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
// MileageRateService.java
@Service
public class MileageRateService {
public float ratePerMile() {
return 0.565f;
}
}
最佳实践
- 使用构造函数注入:优先使用构造函数注入,而不是字段注入,这样可以提高代码的可测试性和可读性。
@Service
public class MileageFeeCalculator {
private final MileageRateService rateService;
@Autowired
public MileageFeeCalculator(MileageRateService rateService) {
this.rateService = rateService;
}
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
- 避免循环依赖:循环依赖会导致依赖注入失败,尽量避免在Bean之间形成循环依赖。
常见问题
1. 使用 @Configurable
注解时的问题
如果使用 @Configurable
注解让Spring对 new
创建的对象进行配置,需要进行额外的配置,如使用AspectJ编译时织入。
2. 测试类中 @Autowired
字段为 null
在测试类中,确保使用正确的注解(如 @RunWith(SpringRunner.class)
和 @SpringBootTest
)来启动Spring上下文。
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
// 测试代码
}
3. 静态字段注入问题
不要对静态字段使用 @Autowired
注解,因为静态字段在类加载时就已经初始化,Spring无法对其进行注入。
上一篇: RequestPar
下一篇: a = null 和