由于之前对@Resource与@Autowired只限于使用,隔久了又忘记了。在此总结此文为后续开发提高效率。在spring项目中关于Controller层、Service层使用@Resource和@Autowired注入bean使用过程中,有时候@Resource 和 @Autowired可以替换使用;有时,则不可以。为什么不可以呢?接下来我们开始通过例子来解答。
1、首先创建一个springmvc的项目,关键类代码如下:
package com.tfq.springaop.service;
/**
*
* @description 汽车接口定义
* @author tangfq;
* @version 2020年5月24日 下午12:21:25
*
**/
public interface ICar {
/**
* 启动引擎
* @return
*/
String startEngine();
}
package com.tfq.springaop.service;
import org.springframework.stereotype.Service;
/**
*
* @description 宝马汽车实现Car接口
* @author tangfq;
* @version 2020年5月24日 下午12:24:26
*
**/
@Service
public class BwCar implements ICar{
/* (non-Javadoc)
* @see com.tfq.springaop.service.ICar#startEngine()
*/
@Override
public String startEngine() {
return "I am driving bw car";
}
}
package com.tfq.springaop.controller;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.tfq.springaop.service.ICar;
/**
*
* @description
* @author tangfq;
* @version 2020年5月24日 下午3:35:44
*
**/
@RestController
@RequestMapping("/car")
public class CarController {
@Resource
private ICar car;
@RequestMapping("/start")
public String startEngine(){
return car.startEngine();
}
}
使用@Resource注入名字为car的bean,但是并没有名字为car的bean,这时就会走byType注入, 所以说这个注入成功是根据byType注入成功的,而不是byName。 其实byType就是根据指定的数据类型自动装配,比如car为ICar实体类。
访问项目的CarController结果如下:
2、改动一:
将CarController.java 类中的注解替换为@Autowired,再次启动,可以正常访问,与上图访问的结果相同,这里不再贴图。这里是使用@Autowired或@Resource都可以。因为ICard只有一个bean实体类。通过两种方式都可以找到注入bean。
查看spring源码:Autowired的多种方式(spring版本4.2.4.RELEASE)
1.构造器注解(constructor)
2.属性setter注解
3.field注解
4.配置方法config method
不管使用上面4中的哪个方法,Spring都会满足声明的依赖。假如有且只有一个bean匹配依赖的话,那么这个bean将会被装配进来。如果有多个bean的话,则用Qualifier指定。
如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,可以使用。关于自动装配详细参考:https://blog.csdn.net/weixin_43277643/article/details/84253237。
3、改动二:
再增加一个实现类BenzCar.java
package com.tfq.springaop.service;
import org.springframework.stereotype.Service;
/**
*
* @description 奔驰汽车
* @author tangfq;
* @version 2020年5月24日 下午9:38:00
*
**/
@Service
public class BenzCar implements ICar{
@Override
public String startEngine() {
return "I am driving Benz car";
}
}
当把CarController.java的ICar修改为@Resource修饰,代码如下:
package com.tfq.springaop.controller;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.tfq.springaop.service.ICar;
/**
*
* @description
* @author tangfq;
* @version 2020年5月24日 下午3:35:44
*
**/
@RestController
@RequestMapping("/car")
public class CarController {
@Resource
private ICar car;
@RequestMapping("/start")
public String startEngine(){
return car.startEngine();
}
}
启动项目访问controller,报错信息:Error creating bean with name 'carController': Injection of resource dependencies failed;No qualifying bean of type [com.tfq.springaop.service.ICar] is defined: expected single matching bean but found 2: benzCar,bwCar.
根据报错可知在CarController类中,ICar没有标识bean实现类,有两个实现类(benzCar、bwCar)不知道取哪一个bean。所以此时要指定一个bean实现类。在ICar上添加如下代码:
@Resource(name="bwCar")
private ICar car;
或者
@Resource
@Qualifier("bwCar")
private ICar car;
访问地址:http://localhost:8080/springaop/car/start,结果如下图:
4、改动三:
在改动二的基础上,将注解替换为@Autowired,启动报错
Could not autowire field: private com.tfq.springaop.service.ICar com.tfq.springaop.controller.CarController.car; nested exception
is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type [com.tfq.springaop.service.ICar] is defined: expected single matching bean but found 2: benzCar,bwCar
根据报错可知在CarController类中,ICar没有标识bean实现类,有两个实现类(benzCar、bwCar)不知道取哪一个bean。
解决:使用@Primary注解,在有多个实现bean时告诉spring首先@Primary修饰的那个;或者使用@Qualifier来标注需要注入的类。
@Qualifier修改方式与改动二的相同,依然是修改CarController.java 中间注入的ICar上面
@Autowired
@Qualifier("benzCar")
private ICar car;
@Primary是修饰实现类的,告诉spring,如果有多个实现类时,优先注入被@Primary注解修饰的那个Service。在CarController可以使用@Resource或@Autowired,我们希望注入BwCar.java ,那么修改BwCar.java为
package com.tfq.springaop.service;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
/**
*
* @description 宝马汽车实现Car接口
* @author tangfq;
* @version 2020年5月24日 下午12:24:26
*
**/
@Service
@Primary
public class BwCar implements ICar{
@Override
public String startEngine() {
return "I am driving bw car";
}
}
package com.tfq.springaop.controller;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.tfq.springaop.service.ICar;
/**
*
* @description
* @author tangfq;
* @version 2020年5月24日 下午3:35:44
*
**/
@RestController
@RequestMapping("/car")
public class CarController {
@Autowired
private ICar car;
@RequestMapping("/start")
public String startEngine(){
return car.startEngine();
}
}
通过以上的例子,他们的相同与不同点如下:
1)共同点
@Resource和@Autowired都可以作为注入属性的修饰,在接口仅有单一实现类时,两个注解的修饰效果相同,可以互相替换,不影响使用。
2)不同点
@Resource是Java自己的注解,@Resource有两个属性是比较重要的,分是name和type;Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Autowired是spring的注解,是spring2.5版本引入的,Autowired只根据type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。
代码参考地址:https://blog.csdn.net/magi1201/article/details/82590106?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase
深入理解Spring IOC参考地址:https://www.cnblogs.com/chenssy/p/9576769.html
项目下载地址:https://github.com/fuqiangt/project
以上为我根据网上的介绍然后结合其他blog的内容和评语总结,等后续有时间在写查看Spring源码深入理解实现原理。如我表述有误请大家评论指出来。