@Autowired @Resource @Inject的区别
来源:互联网 发布:php取字符串的后几位 编辑:程序博客网 时间:2024/05/17 01:16
测试环境:Intellij + gradle
编写build.gradle
group 'com.xiya'version '1.0-SNAPSHOT'apply plugin: 'java'apply plugin: 'idea'sourceCompatibility = 1.8repositories { mavenCentral()}dependencies { testCompile group: 'junit', name: 'junit', version: '4.11' compile group: 'org.springframework', name: 'spring-context', version: '4.3.7.RELEASE'}
Spring存在三种依赖注入的注解:
@Autowired:org.springframework.beans.factory.annotation.Autowired
@Resource:javax.annotation.Resource
@Inject:javax.inject.Inject
三种方式的区别在哪里呢?
测试:
定义Person接口
package com.xiya.entity;/*** @file Person.java* @CopyRight (C) http://blog.csdn.net/x_iya* @Description* @author N3verL4nd* @email lgh1992314@qq.com* @date 2017/6/17*/public interface Person { void sayHello();}
定义两个实现类:
package com.xiya.entity;import org.springframework.stereotype.Component;/*** @file Chinese.java* @CopyRight (C) http://blog.csdn.net/x_iya* @Description* @author N3verL4nd* @email lgh1992314@qq.com* @date 2017/6/17*/@Componentpublic class Chinese implements Person { @Override public void sayHello() { System.out.println("你好,我来自中国!"); }}
package com.xiya.entity;import org.springframework.stereotype.Component;/*** @file American.java* @CopyRight (C) http://blog.csdn.net/x_iya* @Description* @author N3verL4nd* @email lgh1992314@qq.com* @date 2017/6/17*/@Componentpublic class American implements Person { @Override public void sayHello() { System.out.println("Hello, I come from America!"); }}
定义Service层
package com.xiya.service;import com.xiya.entity.Person;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Service;import javax.annotation.Resource;/*** @file PersonManager.java* @CopyRight (C) http://blog.csdn.net/x_iya* @Description* @author N3verL4nd* @email lgh1992314@qq.com* @date 2017/6/17*/@Servicepublic class PersonManager { private Person person; /* 构造器注入 * 使用: * @Autowired * @Qualifier("chinese") * 或者使用: * @Resource(name = "chinese") * */ @Resource(name = "chinese") public void setPeople(Person person) { this.person = person; } public void sayHello() { person.sayHello(); }}
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--配置自动扫描的包--> <context:component-scan base-package="com.xiya.entity, com.xiya.service"> <!--<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>--> <!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>--> </context:component-scan></beans>
测试类:
import com.xiya.service.PersonManager;import org.junit.Before;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class T { private ApplicationContext context; @Before public void setBefore() { context = new ClassPathXmlApplicationContext("applicationContext.xml"); } @Test public void test() { PersonManager peopleManager = context.getBean(PersonManager.class); peopleManager.sayHello(); }}
目录结构:
对于@Autowired
先按类型注入,然后按照名称注入,都无法找到唯一的一个实现类则报错。
我们将American类中@Component注释掉,这样在Spring环境中Person只有Chinese一个实现类
输出:你好
因为只有Chinese实现了Person,所以会正确运行(通过类型查找)。
我们取消American类中@Component的注释,运行程序会出现异常:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'people': Unsatisfied dependency expressed through field 'person'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.xiya.spring.entity.Person' available:expected single matching bean but found 2: american,chinese
因为Person有American和Chinese两个实现类,Spring不知道该用哪一个进行注入。接着按照名称注入,spring容器中没有名字为person的bean。
People修改如下:(Chinese与American类都用@Component注解)
结果会输出:“你好,我来自中国!”。此时变量名chinese等于Chinese默认的Qualifier名字。改为american则输出“Hello, I come from America!”。package com.xiya.service;import com.xiya.entity.Person;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Service;import javax.annotation.Resource;/*** @file PersonManager.java* @CopyRight (C) http://blog.csdn.net/x_iya* @Description* @author N3verL4nd* @email lgh1992314@qq.com* @date 2017/6/17*/@Servicepublic class PersonManager { private Person person; /* 构造器注入 * 使用: * @Autowired * @Qualifier("chinese") * 或者使用: * @Resource(name = "chinese") * */// @Resource(name = "chinese") @Autowired// @Qualifier("chinese") public void setPeople(Person chinese) { this.person = chinese; } public void sayHello() { person.sayHello(); }}
相当于:
@Qualifier("chinese")
如果只有一个实体类Chinese(删除American类),而且Chinese不实现Person接口,此时怎么注入Person chinese都会出错(请求的是Person对象,注入的却不是)。
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'people': Unsatisfied dependency expressed through field 'chinese'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.xiya.spring.entity.Person' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
查找流程:首先在Spring容器内查找类型为Person的bean,没有找到;接着按照chinese名称进行查找,虽然查找到,但是是类型为Chinese,抛异常。
@Autowired(required=false)中如果设置required为false(默认为true),则注入失败时不会抛出异常,但person.sayHello();调用时会出现空指针异常NullPointerException。
对于@Inject
需要引入:
compile group: 'javax.inject', name: 'javax.inject', version: '1'
在Spring的环境下,@Inject和@Autowired是相同的,都是使用AutowiredAnnotationBeanPostProcessor来处理依赖注入,@Inject是jsr-330定义的规范,还是比较推荐使用这种方式进行依赖注入,如果使用这种方式,切换到Guice也是可以的。
如果硬要说两个的区别,首先@Inject是Java EE包里的,在SE环境需要单独引入。另一个区别在于@Autowired可以设置required=false而@Inject并没有这个设置选项。
对于@Resource
先按名字注入,再按类型注入,都无法找到唯一的一个出现异常。
这是jsr-250定义的规范,相对于jsr-330算是比较老的了。这里不推荐使用这种注入方式,下面讨论一下其注入的问题。
首先我们注释American里的@Component,这样在Spring托管的Bean里只有Chinese实现了Person接口,测试用例如下:
@Componentpublic class People { @Resource private Person person; public void sayHello() { person.sayHello(); }}输出结果:“你好,我来自中国!”。 此时@Resource先按名字person,并未找到名称为person的bean,然后按照类型来找,只有Chinese,注入成功。
取消American中的@Component注释,出现如下异常:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'people': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.xiya.spring.entity.Person' available: expected single matching bean but found 2: american,chinese
此时先通过名字无法确定,然后通过类型还是无法确定,抛出异常。
修改测试代码:
@Componentpublic class People { @Resource private Person chinese; public void sayHello() { chinese.sayHello(); }}输出结果你好,此时按名字找到了chinese。
--------------
@Autowired是可以写在字段或者setter方法上或者构造器上。
然而,在字段上使用@Autowired注解,IDEA会提示“Field injection is not recommended.Spring Team recommends:’Always use constructor based dependency injection in your beans.Always use assertions for mandatory dependencies.’” 不推荐使用字段注入,会发生空指针错误,推荐使用构造器注入。
@Componentpublic class People { @Autowired @Qualifier("chinese") private Person person; public void sayHello() { person.sayHello();// NullPointerException发生 }}使用构造器注入则可以避免该问题的发生:
@Componentpublic class People { /*@Autowired @Qualifier("chinese")*/ private Person person; @Autowired public People(@Qualifier("chinese") Person person) { Assert.notNull(person, "person must not be null"); this.person = person; } public void sayHello() { person.sayHello(); }}
- @Autowired @Resource @Inject的区别
- @Resource,@Autowired 和 @Inject的区别
- spring用注解实现注入的@resource,@autowired,@inject区别
- Spring下@Resource, @Autowired和@Inject的区别与联系
- @Inject和@Autowired以及@Resource区别
- @Autowired,@Inject,@Resource
- @Autowired与@Resource的区别
- @Autowired 与@Resource的区别
- @Resource与@Autowired的区别
- @Resource和@Autowired的区别
- @Autowired 与 @Resource的区别
- @Resource和@Autowired的区别
- @autowired和@resource的区别
- @Autowired与@Resource的区别
- @Autowired与@Resource的区别
- @Autowired与@Resource的区别
- @autowired和@resource的区别
- @Autowired与@Resource的区别
- JS中offsetTop、clientTop、scrollTop、offsetTop各属性介绍
- ASP.NET获取客户端网卡使用的MAC地址信息
- 我希望我知道的七个JavaScript技巧 译(转)
- android 单元测试,喵喵喵?(辣鸡用法)
- 实战ASP.NET访问共享文件夹(含详细操作步骤)
- @Autowired @Resource @Inject的区别
- 清空数据库SQL
- JAVA代码备注
- BZOJ P3211 花神游历各国
- error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2”
- 大数问题——Java中的BigDecimal类
- Android中CMake的使用之一初步总结
- 旧约——交通灯改制
- PullToRefreshListView listview 单选多选