Java自动装配

自动装配注解

  • @Autowired
  • @Resource

@Autowired@Resource 都是Spring、SpringBoot 项目中用来进行 “依赖注入” 的注解。
他们都提供了将依赖对象注入到当前对象的功能,但二者却有众多不同,主要体现在以下5点:

  1. 来源不同
  2. 依赖查找的顺序不同
  3. 支持的参数不同
  4. 依赖注入的用法不同
  5. 编译器 IDEA 的提示不同

1、来源不同

@Autowired 和 @Resource 来自不同的父类,其中@Autowired 是 Spring 框架定义的注解,
而@Resource 是Java规范定义的注解。

2、依赖查找顺序不同

@Resource 根据名称(byName)查找,如果(根据名称)查找不到,根据类型(byType)进行查找;
@Autowired 根据类型(byType)查找,如果存在多个(Bean)根据指定的名称(byName)进行查找;

实验说明(@Resource):
// 定义做饭接口Cook.java,抽象方法open()、cooking()、close()
public interface Cook {

	/**
	 * 开火
	 */
	String open();
	/**
	 * 炒菜
	 */
	String cooking();
	/**
	 * 关火
	 */
	String close();
}
/**
 * service接口 实现类
 * 炒西红柿
 */
@Service
public class CookTomato implements Cook {
	@Override
	public String open() {
		return "炒西红柿前打开油烟机并开火";
	}
	@Override
	public String cooking() {
		return "炒西红柿中~";
	}
	@Override
	public String close() {
		return "炒西红柿后关闭油烟机并关火";
	}
}
/**
 * controller层
 */
@RestController
@RequestMapping("/cook")
public class CookController {

    // 依赖注入
	@Resource
	private Cook cook;

	@RequestMapping("/open")
	public String open() {
		return cook.open();
	}

	@RequestMapping("/cooking")
	public String cooking() {
		return cook.cooking();
	}

	@RequestMapping("/close")
	public String close() {
		return cook.close();
	}
}

启动SpringBoot正常启动,请求这三个接口返回的都是正常数据。
如果再添加一个Cook接口的实现类,这会发生一下情况

/**
 * service接口 实现类
 * 炒土豆
 */
@Service
public class CookPatato implements Cook {
	@Override
	public String open() {
		return "炒土豆丝前打开油烟机并开火";
	}
	@Override
	public String cooking() {
		return "炒土豆丝中~";
	}
	@Override
	public String close() {
		return "炒土豆丝后关闭油烟机并关火";
	}
}

这个时候重启SpringBoot项目,这会启动报错。
WARN 5592 — [ restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘CookController’: Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘com.janeroad.annotation.service.Cook’ available: expected single matching bean but found 2: CookTomato,CookPatato
大致意思就是:我们引入Cook但是Spring框架发现了两个实现,无法匹配到底用哪一个。


我们将代码修改一下:

@Resource(name="CookTomato")
private Cook cook;

// 或者

@Resource
@Qualifier("CookTomato")
private Cook cook;

上述代码其实都是在做同一件事,就是把注入的Cook实现类指定为西红柿实现类(CookTomato),再启动项目就能够正常启动了,接口访问也正常。

实验说明2(@Autowire)

基于上边的Controller类,同样是有两个Cook接口的实现类,将依赖注入注解改为@Autowired

/**
 * controller层
 */
@RestController
@RequestMapping("/cook")
public class CookController {

    // 依赖注入
	@Autowire
	private Cook cook;

	@RequestMapping("/open")
	public String open() {
		return cook.open();
	}

	@RequestMapping("/cooking")
	public String cooking() {
		return cook.cooking();
	}

	@RequestMapping("/close")
	public String close() {
		return cook.close();
	}
}
Description:
 
Field cook in com.janeroad.annotation.controller.CookController required a single bean, but 2 were found:
 - cookTomato: defined in file [此处省略路径名]
 - cookPatato: defined in file [此处省略路径名]
//  大致意思:注入cook字段时,找到两个依赖bean,不知道到底要注入哪一个
 
 
Action:
 
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
// 考虑将其中一个bean标记为@Primary,告诉Spring优先使用@primary修饰的类,
// 或者在注入时使用@Qualifier来标识应该被使用的bean

根据错误提示我们有两种解决方案:
1、将多种实现类中的其中一个类标记@Primary注解,告诉Spring优先使用那个Bean
2、在依赖注入的时候,标注一下要注入哪一个Bean

/**
 * service接口 实现类
 * 炒西红柿
 */
@Service
@Primary
public class CookTomato implements Cook {
	@override
	public String open() {
		return "炒西红柿前打开油烟机并开火";
	}
	@override
	public String cooking() {
		return "炒西红柿中~";
	}
	@override
	public String close() {
		return "炒西红柿后关闭油烟机并关火";
	}
}
/**
 * controller层
 */
@RestController
@RequestMapping("/cook")
public class CookController {

    // 依赖注入
	@Autowire
    @Qualifier("CookTomato")
	private Cook cook;

	@RequestMapping("/open")
	public String open() {
		return cook.open();
	}

	@RequestMapping("/cooking")
	public String cooking() {
		return cook.cooking();
	}

	@RequestMapping("/close")
	public String close() {
		return cook.close();
	}
}

3、支持参数不同

@Autowired 和 @Resource 在使用的时候都可以设置参数,比如给@Resource注解设置name和type参数。

@Resource(name="userinfo", type="UserInfo.class")
private UserInfo user;

但是,二者支持的参数以及参数的数量完全不同,其中@Autowired只支持设置一个 required 参数,而@Resource 注解支持7个参数。
@Autowired 参数说明:
image.png

// @Autowired注解只支持一个参数 required 
// 属性required:用于标识依赖对象是否是必须的,默认值为true,如果找不到符合的对象则会抛出异常,
// 如果设置为false,则会忽略找不到匹配对象的情况。

@Resource 参数说明:
image.png

// @Resource注解支持7个参数:
// 1.name:指定需要注入的依赖对象的名称,用于查询找匹配的Bean。默认值为空字符串
@Resource(name="myDependency")
private MyDependency dependency;

// 2.type:指定需要注入的依赖对象的类型,默认值为java.lang.Object,表示任意类型
@Resource(type="MyDependency.class")
private MyDependency dependency;

// 3.lookup:指定依赖对象的JNDI名称,用于查找匹配的资源。默认值为空字符串
@Resource(lookup = "java:/comp/env/myDependency")
private MyDependency dependen

// 4.shareable:指定注入的依赖对象是否共享。默认值为true,表示可以共享
@Resource(shareable = false)
private MyDependency dependency;

// 5.authenticationType:指定在资源查找过程中使用的身份验证类型。默认值为空字符串。
@Resource(authenticationType = "CONTAINER")
private MyDependency dependency;

4、依赖注入的支持不同

常见的依赖注入有三种:

  1. 属性注入
  2. 构造器注入
  3. Setter注入

@Autowired 和 @Resource 支持的依赖注入用法不用,@Autowired注解支持以上三种注入方式,@Resource只支持 属性注入Setter注入 到如果使用@Resource注入构造方法时,就会提示错误。
属性注入:

@RestController
public class UserController {
    // 属性注入
    @Autowired
    private UserService userService;
 
    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

Setter注入:

@RestController
public class UserController {
    // Setter 注入
    private UserService userService;
 
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
 
    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

构造方法注入:

@RestController
public class UserController {
    // 构造方法注入
    private UserService userService;
 
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
 
    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

5、编译器提示不同

当使用 IDEA 专业版在编写依赖注入的代码时,如果注入的是 Mapper 对象,那么使用 @Autowired 编译器会提示报错信息。虽然 IDEA 会出现报错信息,但程序是可以正常执行的。 然后,我们再将依赖注入的注解更改为 @Resource 就不会出现报错信息了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张丶三岁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值