如何避免找到两个bean定义"错误

时间:2014-09-17 09:24:13

标签: java spring

我正在开发一个庞大的应用程序,其中有数千个Spring bean使用注释注册并与@Autowired相互连线 该应用程序将作为"核心"应用程序和我们的客户应该能够自定义添加或覆盖bean。 如果他们需要修改bean,那么通常的方法是扩展类并使Spring上下文注册自定义类而不是" core"一,但这样做Spring会抛出一个错误,因为它找到了同一个接口的两个实现。 我怎样才能做到这一点? 我们的客户如何取消注册"核心类和regster是自定义的吗?

非常感谢!

4 个答案:

答案 0 :(得分:2)

You can use a Qualifier. They identify beans by name, not by type.

您还可以将字段设置为bean列表。

@Autowire
private Foobar[] customizedAndCore;

答案 1 :(得分:2)

最简单的处理方法是使用@Primary注释。 Spring将注入主数据库,而不是使用重复的bean异常进行失败。

答案 2 :(得分:1)

这里是使用@Qualifier和@Autowired注释的基本草稿

以下是Student.java文件的内容:

public class Student {
   private Integer age;
   private String name;

   public void setAge(Integer age) {
      this.age = age;
   }
   public Integer getAge() {
      return age;
   }

   public void setName(String name) {
      this.name = name;
   }
   public String getName() {
      return name;
   }
}

以下是Profile.java文件的内容:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class Profile {
   @Autowired
   @Qualifier("student1")
   //@Qualifier("student2")
   private Student student;

   public Profile(){
      System.out.println("Inside Profile constructor." );
   }

   public void printAge() {
      System.out.println("Age : " + student.getAge() );
   }

   public void printName() {
      System.out.println("Name : " + student.getName() );
   }
}

以下是MainApp.java文件的内容:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = 
             new ClassPathXmlApplicationContext("Beans.xml");

      Profile profile = (Profile) context.getBean("profile");

      profile.printAge();
      profile.printName();
   }
}

考虑以下配置文件Beans.xml的示例:

<?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:annotation-config/>

   <!-- Definition for profile bean -->
   <bean id="profile" class="com.Profile">
   </bean>

   <!-- Definition for student1 bean -->
   <bean id="student1" class="com.Student">
      <property name="name"  value="Zara" />
      <property name="age"  value="11"/>
   </bean>

   <!-- Definition for student2 bean -->
   <bean id="student2" class="com.Student">
      <property name="name"  value="Nuha" />
      <property name="age"  value="2"/>
   </bean>

</beans>

答案 3 :(得分:1)

我认为你有三种一般方法......

  1. 创建子上下文并在子上下文中覆盖父上下文中的bean(它们将替换它们)
  2. 使用个人资料
  3. 在注入bean时使用注释的自定义
  4. 第一种选择意味着客户希望用自己的“核心”取代“核心”时,只需要创建一个新工厂,这是核心工厂的孩子。只要孩子中的bean与核心中的on具有相同的名称,一切都很好。

    第二个意味着默认bean将处于“默认”(无配置文件),然后替换将在特定配置文件中。当该配置文件处于活动状态时,这些替换bean将覆盖无配置文件中的bean。替换仅针对bean名称而不是针对类型进行更改,因此在使用此方法时,您必须确保新bean与原始bean具有相同的名称,而注入注释指定bean的名称ala

    @Inject
    @Named("dataSource")
    private DataSource storageRepository;
    

    第三个选项要求在使用bean

    时在注释中出现以下内容
    @Resource(name = "${dataSource}")
    private DataSource dataSource;
    

    然后在使用它时,您将需要一个名为dataSource的参数,并且需要将其设置为要注入该位置的特定bean名称。 例如

      

    的dataSource = enterpriseDataSource

    然后将名为enterpriseDataSource的bean注入该位置。

    我认为它接近1的方式可以说是最接近你正在寻找的东西。听起来你有一个“核心”工厂,你提供客户所依赖的工厂,因此他们并不真正拥有你的源代码。 AFAIK方法1也是唯一允许按类型自动装配的方法。

    方法2更适合您想要在不同模式下运行...即开发,测试或生产模式。原因是您只能覆盖不在配置文件中的bean。使用这种方法,您不能使用另一个配置文件中的bean覆盖已在配置文件中的bean。

    方法3实际上是我最常使用的方法,因为它不需要配置文件或工厂层次结构,只需更改参数的值就允许交换不同的bean。但我希望我不必继续指定bean名称。其他可能的东西 - 以及我经常使用的东西 - 通过激活不同的配置文件来交换一个全新的配置文件。