Strategy for many DAOs in Spring Java

断了今生、忘了曾经 提交于 2019-12-03 14:42:39

I will have all the DAO s as Spring managed components and inject them into services for loose coupling. Why do you think autowiring beans is bad in a big project.?

Just annotate each DAO class with @Component and replace MyDao mydao = factory.getmyDao() with

@Autowired MyDao myDao;

I dont see much coding/configuration overhead with it.

I've taken a couple of different approaches so far with my projects, and haven't really settled on what's "best." And there may not be a "best" but perhaps a "best for your needs."

First, I went with a base service class.

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

Then in my service classes, I can write simply

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

This works, and it keeps my services tidy from all the autowiring and accessor classes for the dao instance variables. Problem is, I've now got a copy of this base class in each of my services, which frankly, meh, not that big of a deal. But it also sort of produces a code smell because it's not using composition over inheritance where, in essence, a reason for DI is to encourage composition.

A coworker suggested a factory such as yours, and called it ServiceProvider. We autowire this into our services.

@Component
public class ServiceProvider {
    @Autowired FooDAO fooDao;
    public FooDAO getFooDAO() {
        return this.fooDao;
    }
    . . .
    // yadda yadda
}

Then we have something like what you have:

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

And that's pretty darned ugly and really doesn't lend itself to clarity. So, we've dabbled with using just the instance of the provider, and naming it something short and sweet like sp. Then we get

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

And again, it works. And it's probably a better design. And we only autowire the DAOs in one place, rather than into each Service, even though that's not really much of a problem either way. But it makes me feel better even though Me Feeling Better isn't a project requirement (but don't cha think it oughta be?)

I've been thinking we'd combine the two. We'd change BaseService to autowire the ServiceProvider, and then wrap the ugly calls.

public abstract BaseService {
    @Autowired ServiceProvider serviceProvider;

    protected getFooDAO() {
        return this.serviceProvider.getFooDAO();
    }

    protected getBarDAO() {
        return this.serviceProvider.getBarDAO();
    }
}

Makes for nicer shorthand in my services, doesn't require me to autowire each DAO into each service which just gets clunky, in my opinion, but also doesn't have a copy of all those references in each service which, you know, is an utterly ridiculous concern.

The problem that I'm left with is stepping through code in the debugger. Stepping in and out of each of those getWhateverDAO() calls is tedious, and adding a possible step through getServiceProvider() doesn't help things either.

But that's where I'm at with this issue. Frankly, I think I spend so much time thinking about this because it's a great way of avoiding all the truly hard problems our application poses.

Good question.

I think that is is very pity that you started to use DAOFactory. Spring is a super flexible factory, so I really do not understand why do you need other one. Autowiring in spring has a lot of advantages and do not reqire interfaces, so you can easily switch to using spring to access DAOs. IMHO it does not reduce but improves the visibility for other developers.

Moreover if you are thinking about refactoring of DAO layer take a look on GenericDAO from google code: http://code.google.com/p/hibernate-generic-dao/

I had a very good experience with this library. It saves your time. You actually do not need many DAOs. You need exactly one DAO. You obviously can wrap the generic DAO from google code and add your application specific terminology and functionality. But do not add entity specific code there. The entity specific code should be at service layer. No more fragile HQL, no coupling with hibernate if you are using Hibernate criteria API. This library supports both Hibernate and JPA and its API is very simple and strong.

If you use too many DAOs in 1 service you should think about to split 1 service into more lower lever (fine grained) services

If you don't want to annotate your DAO classes or have configuration annotations like @Value polluting them, I see two options:

1. Create a @Configuration with DAO @Beans

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

Then create an @Autowired field for the DAO you need:

@Autowired
private FooDao fooDao;

2. Create a DAO factory @Component

Useful if you need to do some cleanup when the DAOs are destroyed.

@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;
    }
}

Then create an @Autowired field for the factory in the classes you need DAOs:

@Autowired
private DaoFactory daoFactory;

And use it as:

daoFactory.barDao().findAll();
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!