草庐IT

Spring实战之bean重复、指定bean的名字、消除bean的歧义性

小蜗牛的路 2023-07-25 原文

Spring实战之bean重复、指定bean的名字、消除bean的歧义性


Spring实战之Bean的主要装配机制之一-通过Java代码显示装配beanSpring实战之Bean的主要装配机制之一-组件扫描、自动装配bean中,我们了解到bena的转配,但是这是在容器中只有一个同类bean的情况下完成的。如果有同类型实现类的bean呢?这种歧义性会阻碍Spring自动装配属性、构造器参数或方法参数。

自动装配的歧义性示例

解释自动装配的歧义性,如下:

public interface Dessert {
}

@Component
public class Cake implements Dessert{
}

@Component
public class Cookies implements Dessert{
}

@Component
public class IceCream implements Dessert{
}

@Configuration
@ComponentScan
public class TestConfig {
    private Dessert dessert;

    @Autowired
    public void setDessert(Dessert dessert){
        this.dessert = dessert;
    }
}

本例中,Dessert是要一个接口,并且有三个实现类:Cake、Cookies、IceCream。因这三个实现类都使用了@Component注解,在主键扫描的时候,能够发现它们并将它们创建为Sping上下文里的bean,然后Spring在自动装配setDessert()中的Dessert参数时,由于没有唯一、无歧义的可选值,Spring会抛出异常:

Parameter 0 of method setDessert in com.example.springboot.config.TestConfig required a single bean, but 3 were found:
	- cake: defined in file [Cake.class]
	- cookies: defined in file [Cookies.class]
	- iceCream: defined in file [IceCream.class]

怎么解决如上歧义性问题呢?Spring提供的了众多解决方案,接下来我们使用设置首选bean(primary)或者使用限定符(qualifier)。

解决方案

@Primary标示首选bean

当你都喜欢上述Cake、Cookies、IceCream这三个甜点时,选择一个你最喜欢的那个,加上@Primary注解来标示你最喜欢它。在声明bean的时候,通过@Primary注解来设置为首选,告诉Spring,当自动装配遇到歧义性的时候,Spring将会使用首选的bean。

@Primary注解与@Component注解配合使用

代码如下:

@Component
@Primary
public class IceCream implements Dessert {
}

@Primary与JavaConfig配合使用

代码如下:

    @Bean
    @Primary
    public Dessert iceCream(){
        return new IceCream();
    }

综上,在多个bean中选取一个bean成为首选bean。可是如果有多个bean都被加上了@Primary注解,在有多个首选bean的设置时,Spring也会无法选择装配哪个bean了!此时,可以为了解决这种歧义性,可以使用限定符(qualifier)。

@Qualifier限定符

@Qualifier注解是使用限定符的主要方式,它可以与@Autowired和@Inject协同使用,在注入的时候指定想要注入进去的那个bean。
例如,我们要确保将IceCream注入到setDessert()之中,代码如下:

    @Autowired
    @Qualifier("iceCream")
    public void setDessert(Dessert dessert){
        this.dessert = dessert;
    }

@Qualifier(“iceCream”)指向的bean是组件扫描时所创建的bean,即IceCream的实例。
但是需要注意的是,限定符中指定的bean是与注入的bean的名称紧耦合的,对类名称的修改,都会导致限定符失效!

创建自定义限定符

与组件扫描搭配使用

代码如下:

@Component
@Qualifier("cold")
public class IceCream implements Dessert {
}

限定符cold分配给了IceCream bean,没有耦合类名,此时可以随意重构IceCream的类名,而不必担心破会自动装配。在注入时,使用cold限定符就可以了:

    @Autowired
    @Qualifier("cold")
    public void setDessert(Dessert dessert){
        this.dessert = dessert;
    }

与JavaConfig搭配使用

    @Bean
    @Qualifier("cold")
    public Dessert iceCream(){
        return new IceCream();
    }

自定义注解实现限定符效果

自定义一个注解来标示特定bean。

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD,
        ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold {
}

与组件扫描搭配使用

实现类上加上自定义注解:

@Component
@Cold
public class IceCream implements Dessert {
}

注入时,加上自定义注解

    @Autowired
    @Cold
    public void setDessert(Dessert dessert){
        this.dessert = dessert;
    }

与JavaConfig搭配使用

	@Bean
    @Cold//bean声明cold限定符
    public Dessert iceCream(){
        return new IceCream();
    }

    @Autowired
    @Cold//注入cold限定符指定的bean
    public void setDessert(Dessert dessert){
        this.dessert = dessert;
    }

有关Spring实战之bean重复、指定bean的名字、消除bean的歧义性的更多相关文章

  1. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  2. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  3. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  4. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  5. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

  6. ruby-on-rails - Rails - 使用/自定义 URL : '/dashboard' 指定根路径 - 2

    如何使此根路径转到:“/dashboard”而不仅仅是http://example.com?root:to=>'dashboard#index',:constraints=>lambda{|req|!req.session[:user_id].blank?} 最佳答案 您可以通过以下方式实现:root:to=>redirect('/dashboard')match'/dashboard',:to=>"dashboard#index",:constraints=>lambda{|req|!req.session[:user_id].b

  7. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  8. spring.profiles.active和spring.profiles.include的使用及区别说明 - 2

    转自:spring.profiles.active和spring.profiles.include的使用及区别说明下文笔者讲述spring.profiles.active和spring.profiles.include的区别简介说明,如下所示我们都知道,在日常开发中,开发|测试|生产环境都拥有不同的配置信息如:jdbc地址、ip、端口等此时为了避免每次都修改全部信息,我们则可以采用以上的属性处理此类异常spring.profiles.active属性例:配置文件,可使用以下方式定义application-${profile}.properties开发环境配置文件:application-dev

  9. ruby - 正则表达式 - 保存重复捕获的组 - 2

    这就是我做的a="%span.rockets#diamonds.ribbons.forever"a=a.match(/(^\%\w+)([\.|\#]\w+)+/)putsa.inspect这是我得到的#这就是我想要的#帮助?我尝试过但失败了:( 最佳答案 通常,您不能获得任意数量的捕获组,但如果您使用扫描,您可以为您想要捕获的每个标记获得一个匹配:a="%span.rockets#diamonds.ribbons.forever"a=a.scan(/^%\w+|\G[.|#]\w+/)putsa.inspect["%span","

  10. ruby - 引用具有指定索引的枚举器值 - 2

    假设我有一个可枚举对象enum,现在我想获取第三个项目。我知道一种通用方法是转换成数组,然后使用索引访问,如:enum.to_a[2]但这种方式会创建一个临时数组,效率可能很低。现在我使用:enum.each_with_index{|v,i|breakvifi==2}但这非常丑陋和多余。执行此操作最有效的方法是什么? 最佳答案 你可以使用take剥离前三个元素,然后剥离last从take给你的数组中获取第三个元素:third=enum.take(3).last如果您根本不想生成任何数组,那么也许:#Ifenumisn'tanEnum

随机推荐