使用Spring注释实例化同一类的多个bean

Fra*_*ois 46 spring annotations

使用XML配置的Spring bean工厂,我可以使用不同的参数轻松实例化同一个类的多个实例.我怎么能用注释做同样的事情?我想要这样的东西:

@Component(firstName="joe", lastName="smith")
@Component(firstName="mary", lastName="Williams")
public class Person { /* blah blah */ }
Run Code Online (Sandbox Code Playgroud)

Esp*_*pen 32

这是不可能的.你得到一个重复的例外.

在您的实现类中,这与配置数据相差甚远.

如果要使用注释,可以使用Java配置来配置类:

@Configuration
public class PersonConfig {

    @Bean
    public Person personOne() {
        return new Person("Joe", "Smith");
    }

    @Bean
    public Person personTwo() {
        return new Person("Mary", "Williams");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这不是真的不可能,但这是不必要的棘手. (3认同)
  • 但是你为你创建的每个不同的Spring bean使用一个单独的工厂.我相信他希望注释配置在Person类中.我只能在你相对高级的例子中看到一个注释,并且注释不支持几个不同的bean.但是我对你的解决方案的复杂性印象深刻:-) (2认同)

wax*_*wax 16

是的,您可以在自定义BeanFactoryPostProcessor实现的帮助下完成此操作.

这是一个简单的例子.

假设我们有两个组件.一个是对另一个的依赖.

第一部分:

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

 public class MyFirstComponent implements InitializingBean{

    private MySecondComponent asd;

    private MySecondComponent qwe;

    public void afterPropertiesSet() throws Exception {
        Assert.notNull(asd);
        Assert.notNull(qwe);
    }

    public void setAsd(MySecondComponent asd) {
        this.asd = asd;
    }

    public void setQwe(MySecondComponent qwe) {
        this.qwe = qwe;
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,此组件没有什么特别之处.它依赖于MySecondComponent的两个不同实例.

第二部分:

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


@Qualifier(value = "qwe, asd")
public class MySecondComponent implements FactoryBean {

    public Object getObject() throws Exception {
        return new MySecondComponent();
    }

    public Class getObjectType() {
        return MySecondComponent.class;
    }

    public boolean isSingleton() {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

这有点棘手.这里有两件事需要解释.第一个 - @Qualifier - 包含MySecondComponent bean名称的注释.这是标准的,但您可以自由实施.稍后你会看到原因.

第二件事是FactoryBean实现.如果bean实现了这个接口,那么它就是要创建一些其他实例.在我们的例子中,它使用MySecondComponent类型创建实例.

最棘手的部分是BeanFactoryPostProcessor实现:

import java.util.Map;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;


public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        Map<String, Object> map =  configurableListableBeanFactory.getBeansWithAnnotation(Qualifier.class);
        for(Map.Entry<String,Object> entry : map.entrySet()){
            createInstances(configurableListableBeanFactory, entry.getKey(), entry.getValue());
        }

    }

    private void createInstances(
            ConfigurableListableBeanFactory configurableListableBeanFactory,
            String beanName,
            Object bean){
        Qualifier qualifier = bean.getClass().getAnnotation(Qualifier.class);
        for(String name : extractNames(qualifier)){
            Object newBean = configurableListableBeanFactory.getBean(beanName);
            configurableListableBeanFactory.registerSingleton(name.trim(), newBean);
        }
    }

    private String[] extractNames(Qualifier qualifier){
        return qualifier.value().split(",");
    }
}
Run Code Online (Sandbox Code Playgroud)

它有什么作用?它遍历所有使用@Qualifier注释的bean,从注释中提取名称,然后手动创建具有指定名称的此类bean.

这是一个Spring配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="MyBeanFactoryPostProcessor"/>

    <bean class="MySecondComponent"/>


    <bean name="test" class="MyFirstComponent">
        <property name="asd" ref="asd"/>
        <property name="qwe" ref="qwe"/>
    </bean>

</beans>
Run Code Online (Sandbox Code Playgroud)

最后需要注意的是,尽管你可以做到这一点,但你不应该这样做,除非它是必须的,因为这是一种不太自然的配置方式.如果您有多个类实例,最好坚持使用XML配置.


huh*_*rto 8

我只是要解决类似的案件.如果您可以重新定义课程,这可能会有效.

// This is not a @Component
public class Person {

}

@Component
public PersonOne extends Person {
   public PersonOne() {
       super("Joe", "Smith");
   }
}

@Component
public PersonTwo extends Person {
   public PersonTwo() {
    super("Mary","Williams");
   }
}
Run Code Online (Sandbox Code Playgroud)

然后,只要您需要自动装配特定实例,只需使用PersonOne或PersonTwo,其他地方只需使用Person.

  • 这是简单的Java方法 - 更像Spring,使用Spring @Qualifier注释的代码更少. (4认同)