【问题标题】:annotation based factory methods基于注解的工厂方法
【发布时间】:2013-01-24 15:46:17
【问题描述】:

我希望能够自动装配单例 bean (foo)

@Component
public class FooUser {

  @Autowire Foo foo;
}

由另一个单例方法创建 (FooFactory.createFoo)

@Service
public class FooFactory {

  public Foo createFoo() {...}
}

对于 xml,它只是 factory-method。我如何使用注释来做到这一点?

【问题讨论】:

  • 我不认为你可以。我认为 Spring 只能自动装配它管理的 bean。但是如果你有一个工厂类/方法,为什么不直接调用它来获取你的 bean?
  • 也许这个问题是相关的? stackoverflow.com/questions/9598829/…
  • @Marvo:我可以让这个 bean 由 spring 管理。我不知道怎么做。我可以再创建 1 个单例(MiddleManService)并使用它来调用工厂,然后在任何地方调用 @Autowire MiddleManService middleMan 和后来的 middleMan.getFoo()。但为什么?我想要它更简单。我只想要@Autwired Foo foo。 xml很简单。注释呢?

标签: java spring annotations


【解决方案1】:

Spring Boot:工厂方法

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

enum ParsersConst {
    bofa, jpm, wellsforgo
}

interface Parser {
    String readFromFile(String file);
}

class JPM implements Parser {
    @Override
    public String readFromFile(String file) {
        System.out.println("From JPM Parser");
        //LOGIC to read file data
        return "JPM";
    }
}

class Bofa implements Parser {
    @Override
    public String readFromFile(String file) {
        System.out.println("From Bofa Parser");
        //LOGIC to read file data
        return "BOFA";
    }
}

class WellsForgo implements Parser {
    @Override
    public String readFromFile(String file) {
        System.out.println("From Wellsforgo Parser"); 
        //LOGIC to read file data
        return "WellsForgo";
    }
}

class ParserCreator {
    private Map<ParsersConst, Parser> parserMap;

    public Parser createParser(ParsersConst parsConst) {
        Parser parser = parserMap.get(parsConst);
        if (parserMap.get(parsConst) != null) {
            return parser;
        }
        throw new IllegalArgumentException("Unknown Parser");
    }

    public void setParserMap(Map<ParsersConst, Parser> parserMap) {
        this.parserMap = parserMap;
    }
}

@Configuration
class ParserConfig {

    @Bean
    public ParserCreator parserCreatorFactory() {
        ParserCreator factory = new ParserCreator();
        Map<ParsersConst, Parser> map = new HashMap<ParsersConst, Parser>();
        map.put(ParsersConst.bofa, new Bofa());
        map.put(ParsersConst.wellsforgo, new WellsForgo());
        map.put(ParsersConst.jpm, new JPM());
        factory.setParserMap(map);
        return factory;

    }

    @Bean
    public Parser bofa() {
        return parserCreatorFactory().createParser(ParsersConst.bofa);
    }

    @Bean
    public Parser wellsforgo() {
        return parserCreatorFactory().createParser(ParsersConst.wellsforgo);
    }

    @Bean
    public Parser jpm() {
        return parserCreatorFactory().createParser(ParsersConst.jpm);
    }
}

@Component
public class StaticFacotryDemo implements CommandLineRunner {
    @Autowired
    private ApplicationContext context;

    @Override
    public void run(String... args) throws Exception {

        Parser parser = (Parser) context.getBean(ParsersConst.jpm.toString());
        System.out.println(parser.readFromFile("jan_stmt.pdf"));

    }

}

【讨论】:

    【解决方案2】:

    Spring 组件也可以定义工厂方法。截取自documentation

    @Component
    public class FactoryMethodComponent {
    
      @Bean @Qualifier("public")
      public TestBean publicInstance() {
          return new TestBean("publicInstance");
      }
    
      public void doWork() {
          // Component method implementation omitted
      }
    }
    

    【讨论】:

      【解决方案3】:

      使用 FactoryBean Spring 接口。然后你就可以自动连接 T 了


      编辑: BeanFactory 是 Spring 中的一个接口,如果你实现它,你可以创建一个对象工厂,例如:

      public class FooFactoryBean implements FactoryBean<Foo>{
         .................. 
         } 
      

      然后你就可以初始化bean了:

      @Bean
      public FooFactoryBean foo(){ 
            return new FooFactoryBean(); 
          } 
      

      那么如果你自动装配 Foo 它 Spring 将理解 FooFactoryBean 是所需的工厂

         @Autowired
             Foo foo;
      

      【讨论】:

      • 这个答案对我来说没有任何意义。问题中没有提到 T。
      • BeanFactory 是 Spring 中的一个接口,您可以在其中实现它,您可以创建 对象的工厂,例如: public class FooFactoryBean implements FactoryBean{ .... ............. } 然后你可以初始化 bean : public FooFactoryBean foo(){ return new FooFactoryBean();那么如果你自动装配 Foo 它 Spring 将理解 FooFactoryBean 是所需的工厂
      【解决方案4】:

      改用 Java @Configuration

      @Configuration 
      public class Config {
      
          @Bean
          public FooUser fooUser() {
              return new FooUser(foo());
          }
      
          @Bean
          public FooFactory fooFactory() {
              return new FooFactory();
          }
      
          @Bean
          public Foo foo() {
              return fooFactory().createFoo();
          }
      
      }
      

      【讨论】:

      • 那很好,如果你想要它作为一个单例如何定义?
      • 您不必这样做。因为 bean 作用域在 spring 中默认是单例的。
      • 我不会那样做的。不要直接调用方法,而是通过参数使用注入。否则:fooUser().getFoo() != AppContext.getBean(Foo.class)因为你已经手动调用了该方法,在它被spring单例之前
      【解决方案5】:

      你需要 java-config - the @Bean annotation

      将您的类定义为@Configuration,将您的方法定义为@Bean

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多