Spring Java中许多DAO的策略

时间:2012-12-06 18:26:14

标签: java spring dao

我们在现有项目中有许多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>

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

5 个答案:

答案 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();