java.lang.NullPointerException: Cannot invoke “com.atguigu.ioc_02.UserService.sayHello()“
·
最近遇到了这样一个问题:
java.lang.NullPointerException: Cannot invoke "com.atguigu.ioc_02.UserService.sayHello()" because "userService" is null
一开始我以为是Spring的对象没有注册,于是费了老半天在Test类中不停getBean来测试这个方法对应的类到底有没有注册成功:
import com.atguigu.ioc_02.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserServiceTest {
@Test
public void testUserService() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-02.xml");
// 测试userService(单个参数)
try {
UserService userService = (UserService) context.getBean("userService");
System.out.println("✅ userService 创建成功");
userService.sayHello();
} catch (Exception e) {
System.out.println("❌ userService 创建失败: " + e.getMessage());
}
// 测试userService1(三个参数)
try {
UserService userService1 = (UserService) context.getBean("userService1");
System.out.println("✅ userService1 创建成功");
userService1.sayHello();
} catch (Exception e) {
System.out.println("❌ userService1 创建失败: " + e.getMessage());
}
}
}
测试的结果没有问题, 确实是注册成功的。
但是问题其实根本就不是有没有注册成功的问题,而是在于一开始注入的依赖是空的:
package com.atguigu.ioc_02;
public class UserService {
private UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
private int age;
private String name;
public UserService(int age , String name ,UserDao userDao) {
this.userDao = userDao;
this.age = age;
this.name = name;
}
public void sayHello(){
System.out.println("Hello!");
}
}
xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--引用和被引用的组件 必须全在ioc容器-->
<!--1.单个构造函数全部注入-->
<!--
springioc容器是一个高级容器,内部会有缓存动作 1.先创建对象【ioc】 2.再进行属性赋值【di】
-->
<!--步骤1:将它们都存放在ioc容器-->
<bean id="userService" class="com.atguigu.ioc_02.UserService">
<!--构造函数传值 di的配置
<constryctor-arg 构造函数传值的di配置
value = 直接属性赋值 String name = “张三” int age = “18”
ref = 引用其他的bean beanid值
-->
<constructor-arg ref="userDao"/>
</bean>
<bean id="userDao" class="com.atguigu.ioc_02.UserDao"/>
<!--2.多个构造函数的顺序填写-->
<bean id="userService1" class="com.atguigu.ioc_02.UserService">
<!--方案1:构造函数的顺序填写 value直接赋值 ref引用其他的beanid-->
<constructor-arg type="int" value="18"/>
<constructor-arg type="java.lang.String" value="张三"/>
<constructor-arg ref="userDao"/>
</bean>
<bean id="userService2" class="com.atguigu.ioc_02.UserService">
<!--方案2:构造函数的名称填写 不用考虑顺序 name = 构造函数的名字-->
<constructor-arg name="name" value="张三"/>
<constructor-arg name="age" value="18"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
<!--3.触发setter方法进行注入-->
<bean id="movieFinder" class="com.atguigu.ioc_02.MovieFinder"/>
<bean id="simpleMovieLister" class="com.atguigu.ioc_02.SimpleMovieLister">
<!--
name->属性名 setter方法的 去set和首字母小写的值 调用set方法的名
setMovieFinder -> movieFinder
value / ref 二选一 value=“直接属性值” ref=“其他bean的id
-->
<property name="movieName" value="消失的她"/>
<property name="movieFinder" ref="movieFinder"/>
</bean>
</beans>
这里看到其实已经注册成功的
其实是构造器注入的时候注入的字段是空值:(Autowired省略了)
package com.atguigu.ioc_02;
import org.springframework.beans.factory.annotation.Autowired;
public class UserService {
private UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
private int age;
private String name;
public UserService(int age , String name ,UserDao userDao) {
this.userDao = userDao;
this.age = age;
this.name = name;
}
public void sayHello(){
System.out.println("Hello!");
}
}
需要进行修改:添加一个允许加入null值依赖的注解参数:
package com.atguigu.ioc_02;
import org.springframework.beans.factory.annotation.Autowired;
public class UserService {
private UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
private int age;
private String name;
@Autowired(required = false)
public UserService(int age , String name ,UserDao userDao) {
this.userDao = userDao;
this.age = age;
this.name = name;
}
public void sayHello(){
System.out.println("Hello!");
}
}
这样就行了!!
总结:
一定要注意区分到底是依赖注册有问题,还是依赖已经注册了但是状态为空的问题!!!!!
(1)注册问题:NoSuchBeanDefinitionException,启动时报错
(2)依赖状态问题:NullPointerException,运行时报错
如何测试呢?
(1)注册问题:使用getBean进行测试
(2)状态问题:空依赖状态测试即可,测试到底是不是为null
更多推荐


所有评论(0)