Spring FactoryBean用法

时间:2013-05-07 19:53:19

标签: java spring

我有一个应用程序,我希望能够根据属性文件中的值切换DAO实现。 Spring FactoryBean接口看起来很好用,因为我可以通过FactoryBean提供DAO,我可以在其中根据属性值进行切换工作。

然而,this Springsource博客文章的最后一段提到了这个警告:

  

这里需要注意的一点是,它是FactoryBean,而不是factoried对象本身,它位于Spring容器中,享有生命周期钩子和容器服务。返回的实例是暂时的 - Spring对从getObject()返回的内容一无所知,也不会尝试在其上运行任何生命周期挂钩或其他任何内容。

我的DAO对象包含Spring注释@Repository@Transactional。根据上面的段落,如果我通过FactoryBean返回DAO实现,这些注释会被忽略吗?如果是这样,有什么方法可以确保Spring管理FactoryBean返回的bean?

编辑:似乎大多数人都在为此问题提供备用配置解决方案。虽然我对这些建议持开放态度(并且如果它们很好就会对它们进行投票),我的问题实际上与正确的FactoryBean使用有关,我会根据这些问题标记正确的答案。

4 个答案:

答案 0 :(得分:2)

假设你有类似的东西:

public interface FooDao {
   // ...
}

@Repository("firstFooDao")
public class FirstFooDao  implements FooDao {
   //...
}

@Repository("secondFooDao")
public class SecondFooDao  implements FooDao {
   //...
}

您可以创建一个配置类,以根据占位符返回适当的实例(在此示例中为foo):

@Configuration
public class FooDaoConfiguration {

    @Value("${foo}")
    private String foo;

    @Autowired
    private BeanFactory beanFactory;

    @Bean
    @Primary
    public FooDao fooDao() {
        return beanFactory.getBean(foo, FooDao.class);
    }

}

然后您可以在属性文件中切换实现:

#foo=firstFooDao
foo=secondFooDao

这样,你的两个实现都是由spring管理的 - 它与你链接的文档中的示例不同,返回的对象是使用非spring工厂构建的。在这种情况下,所有bean都由spring实例化。配置类选择一个。

答案 1 :(得分:1)

您可以在bean的class属性中使用属性占位符,因此如果您有合理的命名约定,则可以使用

<bean id="customerDao" class="com.example.dao.${dao.type}.CustomerDao">

而不是使用工厂bean。

答案 2 :(得分:0)

使用@Component或XML,像往常一样在Spring上下文中创建DAO实例声明。假设它们都继承了一个公共接口,那么您可以稍后使用List收集它们。有关此类型收集机制的更多信息,请参阅此链接: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-autowired-annotation

例如,在你的DAOFactory中:

@Component
class MyCarDAOFactory implements ApplicationContextAware,FactoryBean<CarDAO> {

// Getters and Setters for the ApplicationContextAware interface..
ApplicationContext ctx;
// ...

  // This will place any class that implements CarDAO from Spring Context.
  @Inject
  List<CarDAO> carDaoEntries;

  // This method returns a CarDAO as classified by its Name property specified in 
  // a property placeholder value ( should it have been set in Spring context 
  // via a PropertyPlaceholder)
  public CarDAO getObject() {
   final String val = ctx.getEnvironment().getProperty("MY_PROPERTY_KEY");
      return CollectionUtils.find(carDaoEntries, new Predicate() {

        public boolean evaluate(Object object) {
            return ((CarDAO) object).getName().startsWith(val);
        }
    });
  }
}

现在,对于这类问题,可能会有更优雅/简单的解决方案,所以如果有人可以的话 请进入,然后请这样做!

答案 3 :(得分:0)

Spring Boot:AbstractFactoryBean的用法

import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AbstractFactoryBean;
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;

import lombok.Getter;
import lombok.Setter;

enum ParsersConst {
    bofafactory, jpmfactory, wellsforgofactory
}

interface Parser {
    String readFromFile(String file);

    void setKey(String key);

    String getKey();
}

class JPM implements Parser {
    private String key;

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

    @Override
    public void setKey(String key) {
        this.key = key;

    }

    @Override
    public String getKey() {
        return key;
    }
}

class Bofa implements Parser {
    private String key;

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

    @Override
    public void setKey(String key) {
        this.key = key;

    }

    @Override
    public String getKey() {
        return key;
    }
}

class WellsForgo implements Parser {
    private String key;

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

    @Override
    public void setKey(String key) {
        this.key = key;

    }

    @Override
    public String getKey() {
        return key;
    }
}

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;
    }
}

@Getter
@Setter
class ParserFactory extends AbstractFactoryBean<Parser> {
    private Parser parser;
    private String key;

    public ParserFactory(Parser parser, String key) {
        this.parser = parser;
        this.key = key;
    }

    @Override
    public Class<?> getObjectType() {
        return parser.getClass();
    }

    @Override
    protected Parser createInstance() throws Exception {
        parser.setKey(key);
        return parser;
    }
}

@Configuration
class ParserConfig {

    @Bean
    public ParserFactory jpmfactory() {
        ParserFactory factory = new ParserFactory(jpm(), "XMYMK1@KML");
        return factory;
    }

    @Bean
    public ParserFactory bofafactory() {
        ParserFactory factory = new ParserFactory(bofa(), "A2344567");
        return factory;
    }

    @Bean
    public ParserFactory wellsforgofactory() {
        ParserFactory factory = new ParserFactory(wellsforgo(), "ABC345AAD");
        return factory;
    }

    @Bean
    public Parser bofa() {
        return new Bofa();
    }

    @Bean
    public Parser wellsforgo() {
        return new WellsForgo();
    }

    @Bean
    public Parser jpm() {
        return new 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.jpmfactory.toString());
        System.out.println(parser.getKey() + " " + parser.readFromFile("hello"));
    }

}