我有一个应用程序,我希望能够根据属性文件中的值切换DAO实现。 Spring FactoryBean接口看起来很好用,因为我可以通过FactoryBean提供DAO,我可以在其中根据属性值进行切换工作。
然而,this Springsource博客文章的最后一段提到了这个警告:
这里需要注意的一点是,它是FactoryBean,而不是factoried对象本身,它位于Spring容器中,享有生命周期钩子和容器服务。返回的实例是暂时的 - Spring对从getObject()返回的内容一无所知,也不会尝试在其上运行任何生命周期挂钩或其他任何内容。
我的DAO对象包含Spring注释@Repository
和@Transactional
。根据上面的段落,如果我通过FactoryBean返回DAO实现,这些注释会被忽略吗?如果是这样,有什么方法可以确保Spring管理FactoryBean返回的bean?
编辑:似乎大多数人都在为此问题提供备用配置解决方案。虽然我对这些建议持开放态度(并且如果它们很好就会对它们进行投票),我的问题实际上与正确的FactoryBean使用有关,我会根据这些问题标记正确的答案。
答案 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"));
}
}