在Spring中依赖注入可以使用@Autowired、@Resource和@Inject来完成,并且在一般的使用中是可以相互替换的(注意是一般),不过三者还是有区别,今天来介绍一下他们的区别:
@Autowired注解:
1.Spring本身替换的注解(org.springframework.beans.factory.annotation.Autowired),需要导入Spring相应的jar包才能使用
2.可以标注的位置:构造器、方法、方法参数、变量域和注解上面
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD,
ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
3.在Spring容器解析@Autowired注解时,使用的后置处理器为AutowiredAnnotationBeanPostProcessor,在这个后置处理的注释中有这么一段:
{@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor} * implementation that autowires annotated fields, setter methods, and arbitrary * config methods. Such members to be injected are detected through annotations: * by default, Spring's {@link Autowired @Autowired} and {@link Value @Value} * annotations. * * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation, * if available, as a direct alternative to Spring's own {@code @Autowired}.
4. @Autowired注解有一个required属性,当指定required属性为false时,意味着在容器中找相应类型的bean,如果找不到则忽略,而不报错(这一条是两个注解所没有的功能)。
5. 默认优先按照类型去容器中找对应的组件,找到就赋值,如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找,如果组件id对象的bean不存在,而且required属性为true,就报错。
6. 支持@Primary注解,让Spring进行自动装配的时候,默认使用首选的bean;
@Resource
1.JSR250规范提供的注解(javax.annotation.Resource),不需要导入格外的包,这个注解在JDK的rt.jar包中
2.可以标注的位置:TYPE(表示可以标注在接口、类、枚举),FIELD(变量域)和METHOD(方法)上面。
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
String name() default "";
String lookup() default "";
Class<?> type() default java.lang.Object.class;
enum AuthenticationType {
CONTAINER,
APPLICATION
}
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default "";
String description() default "";
}
3.在Spring容器解析@Resource注解时,使用的后置处理器为CommonAnnotationBeanPostProcessor,在这个后置处理的注释中有这么一段:
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation * that supports common Java annotations out of the box, in particular the JSR-250 * annotations in the {@code javax.annotation} package. These common Java * annotations are supported in many Java EE 5 technologies (e.g. JSF 1.2), * as well as in Java 6's JAX-WS. * * <p>This post-processor includes support for the {@link javax.annotation.PostConstruct} * and {@link javax.annotation.PreDestroy} annotations - as init annotation * and destroy annotation, respectively - through inheriting from * {@link InitDestroyAnnotationBeanPostProcessor} with pre-configured annotation types. * * <p>The central element is the {@link javax.annotation.Resource} annotation * for annotation-driven injection of named beans, by default from the containing * Spring BeanFactory, with only {@code mappedName} references resolved in JNDI. * The {@link #setAlwaysUseJndiLookup "alwaysUseJndiLookup" flag} enforces JNDI lookups * equivalent to standard Java EE 5 resource injection for {@code name} references * and default names as well. The target beans can be simple POJOs, with no special * requirements other than the type having to match.
4. 默认是按照组件名称进行装配的
5. 支持@Primary注解,不过首先按照会按照名称进行注入bean,如果Spring IOC容器中没有该Bean,则按照@Primary注解标注的bean进行装配(这条是我自己总结的,别人都说不支持,但是代码是不会骗人的,给出验证代码,如有错误,请多指教,这个代码的逻辑其实可以看一下CommonAnnotationBeanPostProcessor是怎么处理的,有时间我来看看源码)
下面验证@Resource默认是按照组件名称进行装配的和持支@Primary注解的:
@Configuration
@ComponentScan({"it.cast.resouce"})
public class ResourceConfig {
@Primary //标有Primary注解,使用@Autowired@Inject注解注解时,优先被加载
@Bean
public Y y1(){
Y y = new Y();
y.setI(0);
return y;
}
}
@Component
public class X {
@Resource //这里使用的是@Resource注解,该注解默认按照组件名称进行装配的,所以会优先加载id为y的bean
private Y y;
public Y getY() {
return y;
}
public void setY(Y y) {
this.y = y;
}
}
@Component
public class Y {
private int i = 2;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
测试一下使用,使用@Resource注解的打印结果:
@Test
public void ResourceConfigTest(){
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ResourceConfig.class);
X bean = context.getBean(X.class);
System.out.println(bean.getY().getI());
}
//输出结果为:
// 2
//从而验证了@Resource默认按照名称进行加载
此时,将@Resource注解的属性名称换成y12,这个bean在容器里面没有的
@Configuration
@ComponentScan({"it.cast.resouce"})
public class ResourceConfig {
@Primary //标有Primary注解,使用@Autowired@Inject注解注解时,优先被加载
@Bean
public Y y1(){
Y y = new Y();
y.setI(0);
return y;
}
}
@Component
public class X {
@Resource //这里使用的是@Resource注解,该注解默认按照组件名称进行装配的,所以会优先加载id为y12的bean,
private Y y12; //如果找不到则按Primary注解标注的bean进行注入
public Y getY() {
return y12;
}
public void setY(Y y) {
this.y12 = y;
}
}
@Component
public class Y {
private int i = 2;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
测试一下使用,使用@Resource注解的打印结果:
@Test
public void ResourceConfigTest(){
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ResourceConfig.class);
X bean = context.getBean(X.class);
System.out.println(bean.getY().getI());
}
//输出结果为:
// 0
//由于没有找到id为y12的bean,所以注入了使用@Primary标注的bean,
//而且整个程序没有报错,所以验证了@Resource支持@Primary注解
此时,将@Resource注解换成@Autowired注解的打印结果:
@Configuration
@ComponentScan({"it.cast.resouce"})
public class ResourceConfig {
@Primary //标有Primary注解,使用@Autowired@Inject注解注解时,优先被加载
@Bean
public Y y1(){
Y y = new Y();
y.setI(0);
return y;
}
}
@Component
public class X {
@Autowired
private Y y; //此时不管名称是y还是y12,都会使用标有Primary注解的bean
public Y getY() {
return y;
}
public void setY(Y y) {
this.y = y;
}
}
@Component
public class Y {
private int i = 2;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
测试一下使用,使用@Autowired注解的打印结果:
@Test
public void ResourceConfigTest(){
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ResourceConfig.class);
X bean = context.getBean(X.class);
System.out.println(bean.getY().getI());
}
//输出结果为:
// 0
//从而验证了@Autowired支持@Primary注解
@Inject
1.JSR330规范提供的注解(javax.inject.Inject),主要导入javax.inject包才能使用
2.可以标注的位置:方法、构造器和变量域中
@Target({ METHOD, CONSTRUCTOR, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Inject {} //该注解中没有任何属性
3.在Spring容器解析@Inject注解时,使用的后置处理器和@Autowired是一样的,都是AutowiredAnnotationBeanPostProcessor。
4.由于@Inject注解没有属性,在加载所需bean失败时,会报错
除了上面的不同点之后,@Inject和@Autowired完全等价。