1

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

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

这里的一个重要收获是,它是 FactoryBean,而不是工厂化对象本身,它存在于 Spring 容器中并享受生命周期钩子和容器服务。返回的实例是瞬态的 - Spring 对您从 getObject() 返回的内容一无所知,并且不会尝试使用任何生命周期挂钩或任何其他内容。

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

编辑:似乎大多数人都在为该问题提供替代配置解决方案。虽然我对这些建议持开放态度(如果它们很好,我会支持它们),但我的问题实际上与正确使用 FactoryBean 有关,我将根据这些问题标记一个正确的答案。

4

4 回答 4

4

假设你有这样的事情:

public interface FooDao {
   // ...
}

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

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

您可以创建一个配置类以基于占位符(在此示例中为 )返回适当的 impelementation 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 实例化。配置类选择一个。

于 2013-05-08T08:41:37.787 回答
1

你可以在 bean 的属性中使用属性占位符class,所以如果你有一个合理的命名约定,你可以有类似的东西

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

而不是使用工厂bean。

于 2013-05-07T20:02:26.927 回答
0

像往常一样使用 @Component 或 XML 在 Spring 上下文中创建 DAO 实例声明。假设它们都继承了一个通用接口,那么您以后可以使用列表将它们全部收集起来。有关此类型收集机制的更多信息,请参阅此链接: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);
        }
    });
  }
}

现在,对于这类问题,可能有一个更优雅/更简单的解决方案,所以如果有人可以插话,那么请这样做!

于 2013-05-08T06:28:15.963 回答
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"));
    }

}
于 2020-05-13T12:12:51.483 回答