我们在现有项目中有许多DAO(目前没有接口,但可以改变)。我们没有为每个DAO类连接一个Spring管理的bean并将它们注入服务层,而是有一个类似的DAO“工厂”:
public class DAOFactory {
private static DAOFactory daoFac;
static{
daoFac = new DAOFactory();
}
private DAOFactory(){}
public static DAOFactory getInstance(){
return daoFac;
}
public MyDAO1 getMyDAO1(){
return new MyDAO1();
}
public MyDAO2 getMyDAO2(){
return new MyDAO2();
}
...
(请注意,MyDAO1和MyDAO2是具体类别)
这允许我们在服务层中轻松添加/调用DAO方法,而不必1.)将DAO接口作为属性添加到服务类2.)通过配置将DAO实现连接到服务方法。 (我们有时在一个服务类中使用多个DAO)。
DAOFactory.getInstance().getMyDAO1().doSomething();
到目前为止,这个策略对我们有用(我们没有太多需要切换实现),但我想知道如果我们能够开始新的更好的方法吗?我考虑将DAO自动装配为bean,但我仍然需要在每个服务类中创建属性来表示正在使用的DAO。在一个大型项目中,我仍然犹豫是否开始自动布线bean - 我们需要为所有开发人员提供可见性。
感觉就像我在一个实体之间紧密耦合,但是更少的代码/配置开销和b。)松散地耦合到接口,但需要大量的代码/配置开销。 / p>
我错过了更好的方法吗?介于两者之间?意见表示欢迎。
答案 0 :(得分:5)
我将所有DAO作为Spring托管组件并将其注入到松散耦合的服务中。为什么你认为autowiring bean在一个大项目中是坏的。?
使用@Component注释每个DAO类
并用{/ p>替换MyDao mydao = factory.getmyDao()
@Autowired
MyDao myDao;
我没有看到很多编码/配置开销。
答案 1 :(得分:3)
到目前为止,我对我的项目采取了几种不同的方法,并没有真正确定什么是“最好的”。并且可能没有“最好的”,但可能是“最适合您的需求。”
首先,我选择了基础服务类。
public abstract BaseService {
@Autowired FooDAO fooDao;
@Autowired BarDAO barDao;
. . .
. . .
protected getFooDAO() {
return this.fooDao;
}
}
然后在我的服务类中,我可以简单地写
Foo foo = getFooDAO().uniqueById(id);
这是有效的,它使我的服务保持整洁的dao实例变量的所有自动装配和访问器类。问题是,我现在已经在我的每个服务中都得到了这个基类的副本,坦率地说,嗯,这不是什么大不了的事。但它也会产生一种代码气味,因为它不是使用组合而不是继承,而实质上,DI的一个原因是鼓励组合。
一位同事建议像你这样的工厂,并称之为ServiceProvider。我们将此服务自动化到我们的服务中。
@Component
public class ServiceProvider {
@Autowired FooDAO fooDao;
public FooDAO getFooDAO() {
return this.fooDao;
}
. . .
// yadda yadda
}
然后我们会拥有你所拥有的东西:
Foo foo = getServiceProvider().getFooDAO().uniqueById(id);
这很丑陋,真的不太清楚。所以,我们只涉及使用提供程序的实例,并将其命名为简短且像sp一样甜。然后我们得到
Foo foo = this.sp.getFooDAO().uniqueById(id);
再一次,它有效。它可能是一个更好的设计。我们只在一个地方自动装载DAO,而不是每个服务,尽管这不是一个问题。但它让我感觉更好,即使 Me Feeling Better 不是项目要求(但不要认为它应该是?)
我一直在想我们将两者结合起来。我们将BaseService更改为自动装配ServiceProvider,然后包装丑陋的调用。
public abstract BaseService {
@Autowired ServiceProvider serviceProvider;
protected getFooDAO() {
return this.serviceProvider.getFooDAO();
}
protected getBarDAO() {
return this.serviceProvider.getBarDAO();
}
}
在我的服务中做出更好的速记,并不要求我将每个DAO自动装配到每个服务中,这些服务只是笨重,在我看来,但也没有每个服务中所有这些引用的副本,你们知道,这是一个完全荒谬的担忧。
我留下的问题是逐步调试调试器中的代码。进入和退出每个getWhateverDAO()调用是很乏味的,并且通过getServiceProvider()添加可能的步骤也没有帮助。
但这就是我遇到这个问题的地方。坦率地说,我认为我花了很多时间思考这个问题,因为这是避免我们的应用所带来的所有真正难题的好方法。
答案 2 :(得分:1)
好问题。
我认为你开始使用DAOFactory
是非常可惜的。 Spring是一个超级灵活的工厂,所以我真的不明白为什么你需要其他的。 Spring中的自动装配具有很多优点,并且不需要接口,因此您可以轻松切换到使用spring访问DAO。恕我直言,它并没有减少,但提高了其他开发人员的可见性。
此外,如果您正在考虑重构DAO层,请查看Google代码中的GenericDAO:http://code.google.com/p/hibernate-generic-dao/
我对这个图书馆有很好的经验。它节省了你的时间。你实际上不需要很多DAO。你只需要一个DAO。您显然可以从Google代码中包装通用DAO并添加特定于应用程序的术语和功能。但是不要在那里添加特定于实体的代码。特定于实体的代码应位于服务层。如果你使用的是Hibernate标准API,就不会有更脆弱的HQL,也不会与hibernate耦合。这个库支持Hibernate和JPA,它的API非常简单和强大。
答案 3 :(得分:0)
如果在一项服务中使用过多的DAO,您应该考虑将1项服务拆分为更低级别的(细粒度)服务
答案 4 :(得分:0)
如果您不想注释您的DAO类或使用@Value
等配置注释来污染它们,我会看到两个选项:
<强> 1。使用DAO @Configuration
s
@Bean
@Configuration
public class DaoConfiguration {
@Value("${db.name}")
private String dbName;
@Value("${foo.table}")
private String fooTable;
@Value("${bar.table}")
private String barTable;
@Bean
private FooDao fooDao() {
return new FooDao(dbName, fooTable);
}
@Bean
private BarDao barDao() {
return new BarDao(dbName, barTable);
}
}
然后为您需要的DAO创建一个@Autowired
字段:
@Autowired
private FooDao fooDao;
<强> 2。创建DAO工厂@Component
如果在销毁DAO时需要进行一些清理,这很有用。
@Component
public class DaoFactory {
@Value("${db.name}")
private String dbName;
@Value("${foo.table}")
private String fooTable;
@Value("${bar.table}")
private String barTable;
private FooDao fooDao;
private BarDao barDao;
@PostConstruct
public void init() {
fooDao = new FooDao(dbName, fooTable);
barDao = new BarDao(dbName, barTable);
}
@PreDestroy
public void destroy() {
try {
fooDao.close();
} catch (Exception e) {
log.error("Failed to clean up FooDao", e);
}
try {
barDao.close();
} catch (Exception e) {
log.error("Failed to clean up BarDao", e);
}
}
public FooDao fooDao() {
return fooDao;
}
public BarDao barDao() {
return barDao;
}
}
然后在您需要DAO的类中为工厂创建一个@Autowired
字段:
@Autowired
private DaoFactory daoFactory;
并将其用作:
daoFactory.barDao().findAll();