Spring's overriding bean

后端 未结 8 1374
忘了有多久
忘了有多久 2020-12-01 03:02

Can we have duplicate names for the same bean id that is mentioned in the XML? If not, then how do we override the bean in Spring?

相关标签:
8条回答
  • 2020-12-01 03:20

    Another good approach not mentioned in other posts is to use PropertyOverrideConfigurer in case you just want to override properties of some beans.

    For example if you want to override the datasource for testing (i.e. use an in-memory database) in another xml config, you just need to use <context:property-override ..."/> in new config and a .properties file containing key-values taking the format beanName.property=newvalue overriding the main props.

    application-mainConfig.xml:

    <bean id="dataSource" 
        class="org.apache.commons.dbcp.BasicDataSource" 
        p:driverClassName="org.postgresql.Driver"
        p:url="jdbc:postgresql://localhost:5432/MyAppDB" 
        p:username="myusername" 
        p:password="mypassword"
        destroy-method="close" />
    

    application-testConfig.xml:

    <import resource="classpath:path/to/file/application-mainConfig.xml"/>
    
    <!-- override bean props -->
    <context:property-override location="classpath:path/to/file/beanOverride.properties"/>
    

    beanOverride.properties:

    dataSource.driverClassName=org.h2.Driver
    dataSource.url=jdbc:h2:mem:MyTestDB
    
    0 讨论(0)
  • 2020-12-01 03:21

    Whether can we declare the same bean id in other xml for other reference e.x.

    Servlet-Initialize.xml

    <bean id="inheritedTestBean"   class="org.springframework.beans.TestBean">
      <property name="name" value="parent"/>
      <property name="age" value="1"/>
    </bean>
    

    Other xml (Document.xml)

    <bean id="inheritedTestBean"  class="org.springframework.beans.Document">
      <property name="name" value="document"/>
      <property name="age" value="1"/>
    </bean>
    
    0 讨论(0)
  • 2020-12-01 03:23

    Any given Spring context can only have one bean for any given id or name. In the case of the XML id attribute, this is enforced by the schema validation. In the case of the name attribute, this is enforced by Spring's logic.

    However, if a context is constructed from two different XML descriptor files, and an id is used by both files, then one will "override" the other. The exact behaviour depends on the ordering of the files when they get loaded by the context.

    So while it's possible, it's not recommended. It's error-prone and fragile, and you'll get no help from Spring if you change the ID of one but not the other.

    0 讨论(0)
  • 2020-12-01 03:28

    Question was more about XML but as annotation are more popular nowadays and it works similarly I'll show by example. Let's create class Foo:

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

    and two Configuration files (you can't create one):

    @Configuration
    public class Configuration1 {
        @Bean
        public Foo foo() {
            Foo foo = new Foo();
            foo.setName("configuration1");
            return foo;
        }
    }
    

    and

    @Configuration
    public class Configuration2 {
        @Bean
        public Foo foo() {
            Foo foo = new Foo();
            foo.setName("configuration2");
            return foo;
        }
    }
    

    and let's see what happens when calling foo.getName():

    @SpringBootApplication
    public class OverridingBeanDefinitionsApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OverridingBeanDefinitionsApplication.class, args);
    
            AnnotationConfigApplicationContext applicationContext =
                    new AnnotationConfigApplicationContext(
                            Configuration1.class, Configuration2.class);
    
            Foo foo = applicationContext.getBean(Foo.class);
            System.out.println(foo.getName());
        }
    }
    

    in this example result is: configuration2. The Spring Container gets all configuration metadata sources and merges bean definitions in those sources. In this example there are two @Beans. Order in which they are fed into ApplicationContext decide. You can flip new AnnotationConfigApplicationContext(Configuration2.class, Configuration1.class); and result will be configuration1.

    0 讨论(0)
  • 2020-12-01 03:30

    Since Spring 3.0 you can use @Primary annotation. As per documentation:

    Indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If exactly one 'primary' bean exists among the candidates, it will be the autowired value. This annotation is semantically equivalent to the element's primary attribute in Spring XML.

    You should use it on Bean definition like this:

    @Bean
    @Primary
    public ExampleBean exampleBean(@Autowired EntityManager em) {
        return new ExampleBeanImpl(em);
    }
    

    or like this:

    @Primary
    @Service
    public class ExampleService implements BaseServive {
    }
    
    0 讨论(0)
  • 2020-12-01 03:31

    An example from official spring manual:

    <bean id="inheritedTestBean" abstract="true"
        class="org.springframework.beans.TestBean">
      <property name="name" value="parent"/>
      <property name="age" value="1"/>
    </bean>
    
    <bean id="inheritsWithDifferentClass"
          class="org.springframework.beans.DerivedTestBean"
          parent="inheritedTestBean" init-method="initialize">
      <property name="name" value="override"/>
      <!-- the age property value of 1 will be inherited from  parent -->
    </bean>
    

    Is that what you was looking for? Updated link

    0 讨论(0)
提交回复
热议问题