专栏首页javathingsSpring 中的自动装配,如果遇到多个实例如何处理?

Spring 中的自动装配,如果遇到多个实例如何处理?

Spring 中的自动装配,如果遇到多个实例如何处理?

标记了@Autowired 注解的字段/方法,会由 Spring 容器自动的赋值一个实例化的对象。@Autowired 总是采用 byType 的方式实现自动装配,只要找到需要装配的类型的实例就行了。有时候 Spring 容器中,同一个类型的实例有多个,那么可能会出现异常,这个时候就需要精确的自动装配,需要用到@Qualifier 注解。

示例

有 2 个类,User 和 Company。

Company

package com.learn.entity;
import org.springframework.stereotype.Component;
 
@Component
public class Company {
 
	public Company() {
		System.out.println("init Company...");
	}
 
	private Integer companyCode = this.hashCode();
 
	public Integer getCompanyCode() {
		return companyCode;
	}
 
	public void setCompanyCode(Integer companyCode) {
		this.companyCode = companyCode;
	}
 
	@Override
	public String toString() {
		return "CompanyCode:" + this.companyCode;
	}
}

User

package com.learn.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
@Component
public class User {	
	public User()
	{
		System.out.println("init user...");
	}
	
	@Autowired
	private Company company;
	public Company getCompany() {
		return company;
	}
 
	public void setCompany(Company company) {
		this.company = company;
	}
}

上面的代码中,User 类中有一个 company 字段,标注了 Autowired,这就说明 Spring 容器中的 User 对象,company 的自动的值会被自动赋值,不会是 null。

配置类,定义自动扫描的路径。

package com.learn;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
 
@Configuration
@ComponentScan("com.learn")
public class Config {
 
}

Main 入口。

Main类

package com.learn;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.learn.entity.User;
 
public class Main {
	public static void main(String[] args) {
		//使用Config.class这个配置类
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
		//根据类型获取实例
		User user= applicationContext.getBean(User.class);
		System.out.println(user.getCompany());
		applicationContext.close();
	}
}

运行后输出: init Company… init user… CompanyCode:475779800 可以看到 User 类中的 company 字段并未主动初始化,但是却有值。

如果有 2 个 Bean 实例

上面的例子改一下

Config配置类

package com.learn;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.learn.entity.Company;
 
@Configuration
@ComponentScan("com.learn")
public class Config {
	@Bean
	public Company getCompany()
	{
		Company c=new Company();
		c.setCompanyCode(99999);
		return c;
	}
}

这时候,Spring 容器中出现了 2 个 Company 的实例,一个是自动扫描得到的,另一个是配置类中配置的。此时,Autowired 会将属性的名称作为组件的 id 去容器中查找,即用 company 作为实例的 id 去匹配实例,那么就又会匹配到自动扫描后生成的那个实例,因为那个实例的名字就是首字母小写的类名 company。

如果必须要以配置类中的实例为优先实例,那么只要在该实例上标注上@Primary 注解,表示默认首先该实例。

@Primary注解

@Configuration
@ComponentScan("com.learn")
public class Config {
 
	@Bean
	@Primary
	public Company getCompany()
	{
		Company c=new Company();
		c.setCompanyCode(99999);
		return c;
		
	}
}

注意,采用@Primary 后,此实例会优先加载,Main 方法运行后,得到的 companyCode 是 99999: init Company… init user… init Company… CompanyCode:99999

当然,也可以更直接的,指定自动绑定的实例。上面的 User 类,修改如下代码:

@Qualifier

@Autowired
@Qualifier("getCompany")
private Company company;

那么 company 注入的时候,会去找 id 为 getCompany 的实例,也就是会找到配置类中配置的实例。

总结

@Autowired 根据类型自动注入对象的实例,如果同一个类型的实例有多个,则会根据实例的 id 名去匹配,但这种不是最好的方式,建议直接用@Qualifier 注解指定需要注入的实例,或者用@Primary 注解标识出首选 Bean,减少不必要的干扰。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring Boot 拦截器如何实现

    Spring Boot 的拦截器概念上和 Servlet Filter 很像,拦截发送到 Controller 的请求和给出的响应。

    水货程序员
  • 为什么 spring 中,不支持 autowired 静态变量?

    因为静态变量是属于本身类的信息,当类加载器加载静态变量时,Spring 的上下文环境还没有被加载,所以不可能为静态变量绑定值。

    水货程序员
  • Spring 中的感知接口

    如其名字一样,实现这种接口的 Bean,能自身感知到容器的存在,容器在操作 Bean 的过程中,会调用感知接口中的方法。Spring 设计的这些接口,等于埋下了...

    水货程序员
  • 【“别跟我不会”系列】Java设计模式之策略模式

    一直以来,笔主想写关于设计模式的系列文章与大家进行交流,但碍于自己经验上尚浅,无法将此讲解透彻,闹了笑话。但千里之行,始于足下,我决定将我自己的工作中我用到的设...

    23号杂货铺
  • Google Protocol Buffers 数据交换协议

    protobuf(Protocol Buffers)是Google推出的一个结构化数据交换协议,用于传递自定义的消息格式,可用于同一台机器的进程间、不同设备进程...

    Yano_nankai
  • 设计模式之中介者模式(mediator模式)引入中介者模式中介者模式的实例中介者模式分析

    大家想象一下有十个人要共同完成一个工作,他们要互相合作和沟通,并且根据对方的通知可能要改变自己的状态,但这通常会带来很多问题,流程过于复杂,使得每个人不仅要专注...

    desperate633
  • 桥接模式

    桥接模式是一种对象结构型模式,是将抽象部分与它的实现部分 分离,使它们都可以独立地变化,其主要对象有:

    晚上没宵夜
  • springboot整合druid连接池

    喜欢天文的pony站长
  • .NET Core微服务之基于MassTransit实现数据最终一致性(Part 1)

      关于数据一致性的文章,园子里已经有很多了,如果你还不了解,那么可以通过以下的几篇文章去快速地了解了解,有个感性认识即可。

    Edison Zhou
  • C#自定义事件:属性改变引发事件示例

    1 using System; 2 using System.Collections.Generic; 3 using System.Linq; ...

    CNXY

扫码关注云+社区

领取腾讯云代金券