@Autowired和@Resource和getBean()区别
今天遇到一个对我来说很奇葩的错误,我想在Service中注入bean,我这里使用了@Autowired和@Resource都不能注入,导致初始化失败,使用了getBean()方法就可以注入。从来没有遇到过这个问题。后来我查询了一下,才明白了原理。我的getBean()方法如下:
@Service
public class BeanUtils implements ApplicationContextAware {private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public static <T> T getBean(Class<T> clazz) {return applicationContext.getBean(clazz);}
}
@Autowired
特性:
这是Spring框架提供的注解,支持自动依赖注入。
可以应用于构造函数、方法、字段等。
注入方式:
按类型注入:Spring会在容器中查找与类型匹配的Bean。
可结合@Qualifier:如果存在多个同类型的Bean,可以使用@Qualifier来指定具体的Bean。
required属性:
默认情况下,@Autowired的required属性为true,即要求必须找到对应的Bean。如果找不到,Spring会抛出异常。
设置为false后,如果找不到对应的Bean,注入的字段会被赋值为null。
@Autowired 和 @Resource 的区别
@Autowired
-
特性:
- 这是Spring框架提供的注解,支持自动依赖注入。
- 可以应用于构造函数、方法、字段等。
-
注入方式:
- 按类型注入:Spring会在容器中查找与类型匹配的Bean。
- 可结合
@Qualifier
:如果存在多个同类型的Bean,可以使用@Qualifier
来指定具体的Bean。
-
required
属性:- 默认情况下,
@Autowired
的required
属性为true
,即要求必须找到对应的Bean。如果找不到,Spring会抛出异常。 - 设置为
false
后,如果找不到对应的Bean,注入的字段会被赋值为null
。
- 默认情况下,
@Resource
-
特性:
- 这是来自Java EE的注解,常用于JNDI资源的注入。
- 也可以用于字段或方法。
-
注入方式:
- 按名称优先:默认情况下,
@Resource
会首先根据字段名查找Bean。如果找不到,再按类型查找。 - 如果使用
name
属性,可以显式指定要注入的Bean名称。
- 按名称优先:默认情况下,
-
没有
required
属性:@Resource
没有类似@Autowired
的required
属性,无法控制注入失败时的行为。
为什么有时注解无法注入Bean?
-
注入时机:
- Spring的依赖注入发生在容器启动时,如果在构造器中试图注入的Bean尚未初始化,可能导致注入失败。这在Bean之间相互依赖时尤为明显。
-
作用域问题:
- 如果一个单例Bean试图注入一个原型Bean,Spring可能只会注入单例Bean的一个实例,而不是每次调用都获取一个新的原型Bean。这种情况下,使用
getBean
可以获取最新的原型实例。
- 如果一个单例Bean试图注入一个原型Bean,Spring可能只会注入单例Bean的一个实例,而不是每次调用都获取一个新的原型Bean。这种情况下,使用
-
条件性注入:
- 使用
@Profile
、@Conditional
等注解时,某些Bean可能会因条件未满足而未被创建,导致注入失败。这时手动调用getBean
可以获取已经创建的Bean。
- 使用
-
依赖顺序:
- 在复杂的依赖关系中,可能会出现注入顺序问题。如果一个Bean依赖于另一个尚未创建的Bean,Spring可能无法正确处理这类依赖,导致注入失败。手动调用
getBean
可以避开这个问题。
- 在复杂的依赖关系中,可能会出现注入顺序问题。如果一个Bean依赖于另一个尚未创建的Bean,Spring可能无法正确处理这类依赖,导致注入失败。手动调用
示例
@Service
public class A {@Autowiredprivate B b; // 如果B尚未初始化,这里可能会失败public void doSomething() {// 使用b的功能}
}@Service
public class B {@Autowiredprivate A a; // A依赖B,可能导致循环依赖
}