Spring注册失败
# 问题描述
当使用 @AutoWired 标记类的 成员变量a 做自动注入时,当我们使用new的方式创建类对象A时,就会发现A中的a 为空。 强行使用a,就会报错: java.lang.NullPointerException
例:任务A对任务B的调用,代码如下
@Component
public class TaskA {
@Autowired
TaskB taskB;
void run() {
System.out.println("TaskA is run");
taskB.run();
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
@Component
public class TaskB {
void run() {
System.out.println("TaskB is run");
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
调用A的方式:
@SpringBootApplication
public class Demo40 implements CommandLineRunner {
@Autowired
TaskA taskA;
@Override
public void run(String... args) throws Exception {
// 方式1:@Autowired注解的对象进行调用
System.out.println("test1:");
taskA.run();
}
public static void main(String[] args) {
SpringApplication.run(Demo40.class, args);
System.out.println("test2:");
// 方式2: new初始化的变量进行调用
try {
TaskA task = new TaskA();
task.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
结果:
test1:
TaskA is run
TaskB is run
test2:
TaskA is run
java.lang.NullPointerException
at com.spring.demo40.TaskA.run(TaskA.java:14)
at com.spring.demo40.Demo40.main(Demo40.java:27)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 原因
依赖注入的主要目的是让容器去产生一个对象的实例,然后交给spring容器管理,在整个生命周期中使用他们,更加方便灵活。
@Autowired是根据类型进行自动装配,并且是从容器中获取实例并进行注入,我们称之为依赖注入。
而new()是直接创建一个新的对象。
这个是他们最本质的区别,一个是从spring容器获取,一个是直接创建新对象。即Autowired是全局实例,而new创建的是仅可以在当前类使用。
# 思路
既然New不是使用spring容器获取,那就意味着:如果通过Spring容器获取,就可以随时随地创建程序需要的对象。
这是我们需要引入:ApplicationContextAware
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext var1) throws BeansException;
}
1
2
3
2
3
程序启动后,Spring容器会检测容器中的所有Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的 setApplicationContextAware() 方法,并将容器 ApplicationContext 本身作为参数传给该方法。
如果这时将,ApplicationContext 存入变量中,后面就可以直接使用,ApplicationContext实例来进行从Spring容器取对象的操作。
# 代码方案:
/**
* 动态加载Bean
*/
@Component
public class SpringContextUtil implements ApplicationContextAware {
// Spring应用上下文
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
使用方式:
System.out.println("test3:");
// 方式3: 通过SpringContext封装创建
try {
TaskA task = SpringContextUtil.getBean(TaskA.class);
task.run();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("test4:");
// 方式4: 通过SpringContext封装创建
try {
TaskA task = (TaskA) SpringContextUtil.getBean("taskA");
task.run();
} catch (Exception e) {
e.printStackTrace();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
编辑 (opens new window)
上次更新: 2023/03/17, 15:46:47