Spring Java中许多DAO的策略

我们在现有项目中有许多DAO(目前没有接口,但可以改变)。 我们有一个DAO“工厂”,它不是为每个DAO类连接一个Spring管理的bean,而是将它们注入服务层,如下所示:

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自动assembly为bean,但我仍然需要在每个服务类中创建属性来表示正在使用的DAO。 在一个大型项目中,我仍然犹豫是否开始自动布线bean – 我们需要为所有开发人员提供可见性。

感觉就像我在一个实现紧密耦合的情况下翻转,但是代码/配置开销较少,而b。)松散地耦合到接口,但需要大量的代码/配置开销。

有没有更好的方法我错过了? 介于两者之间? 意见表示欢迎。

我将把所有DAO作为Spring托管组件并将它们注入松散耦合的服务中。 为什么你认为autowiring bean在一个大项目中是坏的。

只需使用@Component注释每个DAO类,并将MyDao mydao = factory.getmyDao()替换为

@Autowired MyDao myDao;

我没有看到它的编码/配置开销。

到目前为止,我对我的项目采取了几种不同的方法,并没有真正确定什么是“最好的”。 可能没有“最好的”,但可能是“最符合您需求的”。

首先,我选择了基础服务类。

 public abstract BaseService { @Autowired FooDAO fooDao; @Autowired BarDAO barDao; . . . . . . protected getFooDAO() { return this.fooDao; } } 

然后在我的服务类中,我可以简单地写

 Foo foo = getFooDAO().uniqueById(id); 

这是有效的,它使我的服务保持整洁的dao实例变量的所有自动assembly和访问器类。 问题是,我现在已经在我的每个服务中都得到了这个基类的副本,坦率地说,嗯,这不是什么大不了的事。 但它也会产生一种代码气味,因为它不是使用组合而不是inheritance,而实质上,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,而不是每个服务,尽管这不是一个问题。 但它让我感觉更好,即使我感觉更好不是一个项目要求(但不要认为它应该是?)

我一直在想我们将两者结合起来。 我们将BaseService更改为自动assemblyServiceProvider,然后包装丑陋的调用。

 public abstract BaseService { @Autowired ServiceProvider serviceProvider; protected getFooDAO() { return this.serviceProvider.getFooDAO(); } protected getBarDAO() { return this.serviceProvider.getBarDAO(); } } 

在我的服务中做出更好的速记,并不要求我将每个DAO自动装入每个服务中,这些服务只是笨拙,在我看来,但也没有每个服务中所有这些引用的副本,你知道,一个完全荒谬的担忧。

我留下的问题是逐步调试调试器中的代码。 进入和退出每个getWhateverDAO()调用是很乏味的,并且通过getServiceProvider()添加可能的步骤也没有帮助。

但这就是我对这个问题的看法。 坦率地说,我认为我花了很多时间思考这个问题,因为这是避免我们的应用程序所带来的所有真正难题的好方法。

好问题。

我认为你开始使用DAOFactory是非常可惜的。 Spring是一个超级灵活的工厂,所以我真的不明白为什么你需要其他的。 Spring中的自动assembly有很多优点,不需要接口,因此您可以轻松切换到使用spring访问DAO。 恕我直言,它并没有减少,但提高了其他开发人员的可见性。

此外,如果您正在考虑重构DAO层,请查看Google代码中的GenericDAO: http : //code.google.com/p/hibernate-generic-dao/

我对这个图书馆有很好的经验。 它可以节省您的时间。 实际上你不需要很多DAO。 你只需要一个DAO。 您显然可以从Google代码中包装通用DAO并添加特定于应用程序的术语和function。 但是不要在那里添加特定于实体的代码。 特定于实体的代码应位于服务层。 没有更脆弱的HQL,如果你使用的是Hibernate标准API,就不会与hibernate耦合。 这个库支持Hibernate和JPA,它的API非常简单和强大。

如果在一项服务中使用过多的DAO,则应考虑将1项服务拆分为更低级别的(细粒度)服务

如果您不想注释DAO类或者有@Value等配置注释@Value污染它们,我会看到两个选项:

1.使用DAO @Bean创建@Configuration

 @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();