2012-12-06 12 views
5

Abbiamo molti DAO in un progetto esistente (attualmente senza interfacce, ma che può cambiare). Piuttosto che il cablaggio di un bean gestito a molla per ogni classe DAO e iniettando loro nel livello di servizio, abbiamo una DAO "fabbrica" ​​di sorta che assomiglia a questo:Strategia per molti DAO nella primavera del Java

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(); 
} 
    ... 

(Si noti che MyDAO1 e MyDAO2 sono classi concrete

Questo ci consente di aggiungere/chiamare facilmente metodi DAO all'interno del livello Servizio, senza dover 1.) aggiungere un'interfaccia DAO come proprietà alla classe di servizio 2.) collegare l'implementazione DAO al metodo di servizio tramite la configurazione. (E a volte utilizziamo più DAO in una classe di servizio).

DAOFactory.getInstance().getMyDAO1().doSomething(); 

Questa strategia ha funzionato per noi finora (non abbiamo avuto bisogno di molto per il passaggio implementazioni), ma mi chiedo se c'è un metodo migliore se siamo stati in grado di iniziare di nuovo? Ho guardato i autowiring DAO i fagioli, ma mi piacerebbe ancora bisogno di creare proprietà di ogni classe di servizio per rappresentare quei DAO utilizzati. E in un grande progetto, io sono riluttanti a iniziare fagioli auto-cablaggio in ogni caso - abbiamo bisogno di fornire visibilità per tutti gli sviluppatori.

Sembra come se flip-flopping tra a.) Essendo strettamente accoppiato a un'implementazione, ma meno overhead di codice/config e b.) Essendo accoppiato liberamente alle interfacce, ma richiedendo un sacco di sovraccarico di codice/configurazione.

C'è un modo migliore che mi manca? Qualcosa in mezzo? Opinioni accolte

+3

Perché usate primavera se non lo fai come l'iniezione di dipendenza? Basta scovare i DAO nelle classi di servizio: ecco cosa sono Sring e DI. Quindi scrivi un test unitario per il tuo servizio iniettando un DAO simulato e considera quanto è più facile provarlo che con una fabbrica statica. –

+2

Abbiamo una classe simile a quella che stai provando qui, ma come menziona JB Nizet, abbiamo inserito i DAO in esso. Una cosa fondamentale nell'autowiring dei DAO è che Spring li gestisce in Singletons per impostazione predefinita, quindi non si otterrà molta creazione di oggetti. L'esempio di codice crea una nuova copia di ogni DAO ogni volta che è necessario utilizzare un determinato DAO e non dovrebbe esserci alcuna necessità. – Marvo

+0

@JB Nizet: Usiamo l'abbondanza DI, non solo per i DAO. Non ho ideato questo metodo, ma ho la possibilità di rielaborarlo, da qui la domanda. –

risposta

5

avrò tutta la DAO s come Spring gestiti componenti e iniettare in servizi per accoppiamento lasco. Perché pensi che i fagioli autowiring siano dannosi in un grande progetto?

Basta annotare ogni classe DAO con @Component e sostituirlo con MyDao mydao = factory.getmyDao()

@Autowired MyDao myDao;

non vedo molto in alto codifica/configurazione con esso.

0

Se si utilizzano troppi DAO in 1 servizio si dovrebbe pensare di dividere 1 servizio in leva più bassa (a grana fine) servizi

1

Buona domanda.

Penso che sia è molto peccato che hai iniziato a utilizzare DAOFactory. La primavera è una fabbrica super flessibile, quindi davvero non capisco perché ne hai bisogno. L'autowiring in primavera ha molti vantaggi e non richiede interfacce, quindi puoi facilmente passare all'utilizzo di spring per accedere ai DAO. IMHO non riduce ma migliora la visibilità per altri sviluppatori.

Inoltre, se stai pensando di refactoring dello strato DAO dare uno sguardo su GenericDAO da Google Code: http://code.google.com/p/hibernate-generic-dao/

ho avuto un'ottima esperienza con questa libreria. Ti fa risparmiare tempo. In realtà non hai bisogno di molti DAO. Hai bisogno esattamente di un DAO. Ovviamente puoi avvolgere il DAO generico dal codice google e aggiungere la terminologia e le funzionalità specifiche dell'applicazione. Ma non aggiungere codice specifico per l'entità lì. Il codice specifico dell'entità dovrebbe essere al livello di servizio. Niente più HQL fragile, nessun accoppiamento con l'ibernazione se si utilizza l'API di criteri Hibernate. Questa libreria supporta sia Hibernate che JPA e la sua API è molto semplice e potente.

3

Ho preso un paio di approcci diversi finora con i miei progetti e non ho ancora deciso cosa sia "il migliore". E potrebbe non esserci un "migliore" ma forse un "migliore per le tue esigenze".

In primo luogo, sono andato con una classe di servizio di base.

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

Poi nelle mie classi di servizio, posso scrivere semplicemente

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

Questo funziona, e mantiene i miei servizi ordinate da tutte le classi autowiring e di accesso per le variabili di istanza dao. Il problema è che ora ho una copia di questa classe base in ciascuno dei miei servizi, il che, francamente, non è un grosso problema. Ma produce anche un odore di codice perché non sta usando la composizione sull'ereditarietà dove, in sostanza, una ragione per DI è incoraggiare la composizione.

Un collaboratore ha suggerito una fabbrica come la tua e lo ha chiamato ServiceProvider. Noi forniamo questo servizio ai nostri servizi.

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

Allora abbiamo qualcosa di simile a quello che hai:

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

E questo è dannatamente brutto e davvero non si presta alla chiarezza. Quindi, ci siamo dilettati a usare solo l'istanza del provider, e nominandolo qualcosa di breve e dolce come sp. Quindi otteniamo

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

E ancora, funziona. Ed è probabilmente un design migliore. E noi solo autowire i DAO in un posto, piuttosto che in ogni servizio, anche se questo non è davvero un gran problema in entrambi i casi. Ma mi fa sentire meglio anche se Me Feeling Better non è un requisito di progetto (ma non credo che cha oughta essere?)

ho pensato che avremmo combinare le due cose. Dovremmo cambiare BaseService per rendere autosufficiente ServiceProvider e quindi avvolgere le brutte chiamate.

public abstract BaseService { 
    @Autowired ServiceProvider serviceProvider; 

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

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

Rende per stenografia più bello nei miei servizi, non mi richiede di autowire ogni DAO in ogni servizio che ottiene appena goffo, a mio parere, ma anche non avere una copia di tutti quei riferimenti a ogni servizio che, sapete, è una preoccupazione assolutamente ridicola.

Il problema che mi rimane è passare il codice nel debugger. Entrare e uscire da ognuna di quelle chiamate getWhateverDAO() è noioso, e l'aggiunta di un possibile passaggio attraverso getServiceProvider() non aiuta neanche le cose.

Ma questo è il punto in cui mi trovo con questo problema. Francamente, penso di spendere così tanto tempo a pensarci, perché è un ottimo modo per evitare tutti i problemi veramente difficili che la nostra applicazione pone.

0

Se non si desidera annotare le vostre classi DAO o hanno annotazioni di configurazione come @Value li inquinanti, vedo due opzioni:

1.Creare un @Configuration con DAO @Bean s

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

Quindi creare un campo @Autowired per il DAO è necessario:

@Autowired 
private FooDao fooDao; 

2. Creare una fabbrica DAO @Component

Utile se avete bisogno fare un po 'di pulizia quando i DAO vengono distrutti.

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

Poi creare un campo @Autowired per la fabbrica nelle classi è necessario DAO:

@Autowired 
private DaoFactory daoFactory; 

e usarlo come:

daoFactory.barDao().findAll(); 
Problemi correlati