如何使用spring java配置在单例bean中生成原型对象

jav*_*Man 6 java spring spring-mvc java-ee

这就是我现在的工作正常.它所做的只是一个返回项目对象数组的市场类:

我有上课的市场

class market {

    public ArrayList<Items> createItems(HashMap<String,String> map) {
        ArrayList<Items> array = new ArrayList<Items>();
        for (Map.Entry<String, String> m : map.entrySet()) {
            Item item = new Item();
            item.setName(m.key());
            item.setValue(m.value());
            array.add(item);
        }
        return array;
    }
}
Run Code Online (Sandbox Code Playgroud)

class Item是带有getter和setter的名称和值的简单类

以下是我的配置文件的外观:

@Configuration
public class MarketConfig {

    @Bean
    public Market market() {
        return new Market();
    }
}
Run Code Online (Sandbox Code Playgroud)

我想如何改变我的代码:(原因:我不想要

Item item = new Item(); 
Run Code Online (Sandbox Code Playgroud)

在那时的方法.我希望Spring将它注入市场)

class market {

    public Item item;
    //getters and setters for item

    public ArrayList<Items> createItems(HashMap<String,String> map) {
        ArrayList<Items> array = new ArrayList<Items>();
        for (Map.Entry<String, String> m : map.entrySet()) {
             item.setName(m.key());
             item.setValue(m.value());
             array.add(item);
        }
        return array;
    }
}

@Configuration
public class MarketConfig {

    @Bean
    @Scope("prototype")
    public Item item() {
        return new Item();
    }

    @Bean
    public Market market() {
        Market bean = new Market();
        bean.setItem(item());
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道每次调用item()时原型范围都会给我新的bean; 现在我想在createItems方法的for循环中为每次迭代创建新bean.我怎么能告诉春天给我.

我知道的一种方式是做

applicationContext context = new AnnotationConfigApplicationContext();
context.getBean(Item.class);
Run Code Online (Sandbox Code Playgroud)

但还有其他方法可以完成我的工作.谢谢

dan*_*nik 20

是的,您可以使用查找方法按需创建原型方法

public abstract class ItemFactory {

    public abstract Item createItem();

}
Run Code Online (Sandbox Code Playgroud)

现在在applicationContext.xml中只需输入以下内容:

<bean id="item" class="x.y.z.Item" scope="prototype" lazy-init="true"/>
Run Code Online (Sandbox Code Playgroud)

并配置工厂:

<bean id="itemFactory" class="x.y.z.ItemFactory">
<lookup-method name="createItem" bean="item"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

现在你需要做的就是在任何bean里面自动装配它:

并打电话给你查询方法:

@Service 
public class MyService{

   @Autowired
   ItemFactory itemFactory;

   public someMethod(){
      Item item = itemFactrory.createItem();
   } 

}
Run Code Online (Sandbox Code Playgroud)

每次调用时,createItem()您都会收到对新创建的Item类实例的引用.

PS:我看到你正在使用@Configuration而不是xml,你需要检查是否可以在配置bean中配置查找方法.

希望能帮助到你.

更新:诀窍很简单:

@Configuration
public class BeanConfig {

    @Bean
    @Scope(value="prototype")
    public Item item(){
        return new Item();
    }


    @Bean
    public ItemManager itemManager(){
        return new ItemManager() {

            @Override
            public Item createItem() {
                return item();
            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)


Ego*_*nko 5

如果您使用的是Java 8,则可以简化它

@Configuration
public class Config {

  @Bean
  @Scope(value = "prototype")
  public Item item() {
      return new Item();
  }

  @Bean
  public Supplier<Item> itemSupplier() {
      return this::item;
  }
}
Run Code Online (Sandbox Code Playgroud)

之后,您可以在Market类中使用此供应商来创建原型Item bean.

@Component
public class Market {

  private final Supplier<Item> itemSupplier;

  @Autowired
  public Market(Supplier<Item> itemSupplier) {
      this.itemSupplier = itemSupplier;
  }

  private Item createItem() {
      return itemSupplier.get();
  }

}
Run Code Online (Sandbox Code Playgroud)

非常简单,不需要额外的工厂bean或接口.