2012-12-06 4 views
5

Wir haben viele DAOs in einem bestehenden Projekt (derzeit ohne Schnittstellen, aber das kann sich ändern). Anstatt Verdrahtung eines Feder Managed Bean für jede DAO-Klasse und in der Dienstschicht injizieren, haben wir eine DAO „Fabrik“ von Sorten, die wie folgt aussieht:Strategie für viele DAOs in Spring 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(); 
} 
    ... 

(Beachten Sie, dass MyDAO1 und MyDAO2 konkrete Klassen sind)

Dies ermöglicht uns das einfache Hinzufügen/Aufrufen von DAO-Methoden innerhalb der Service-Schicht, ohne 1.) eine DAO-Schnittstelle als Eigenschaft der Serviceklasse hinzufügen 2.) die DAO-Implementierung über die Konfiguration in die Service-Methode einbinden. (Und wir verwenden manchmal mehrere DAOs in einer Serviceklasse).

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

Diese Strategie hat sich bisher für uns gearbeitet (wir haben für das Schalten Implementierungen viel Bedarf nicht hatte), aber ich frage mich, ob es eine bessere Methode ist, wenn wir neu anfangen konnten? Ich betrachtete das Autowiren der DAOs als Beans, aber ich müsste trotzdem Eigenschaften in jeder Serviceklasse erstellen, um die verwendeten DAOs darzustellen. Und in einem großen Projekt zögere ich ohnehin, mit der automatischen Verdrahtung von Beans zu beginnen - wir müssen Sichtbarkeit für alle Entwickler bereitstellen.

Es fühlt sich an, als wäre ich zwischen a.) Fest gekoppelt an eine Implementierung, aber weniger code/config overhead und b.) Lose an Schnittstellen gekoppelt, aber mit viel Code/Konfigurationsaufwand.

Gibt es einen besseren Weg, den ich vermisse? Irgendwas dazwischen? Meinungen wurden begrüßt.

+3

Warum verwenden Sie Frühling, wenn Sie nicht tun wie Abhängigkeitsinjektion? Autowire die DAOs in den Serviceklassen: Genau darum geht es bei Sring und DI. Schreiben Sie dann einen Komponententest für Ihren Service, indem Sie ein Pseudo-DAO einwerfen und überlegen, wie viel einfacher es ist, es zu testen als mit einer statischen Fabrik. –

+2

Wir haben eine Klasse, die derjenigen ähnlich ist, die Sie hier versuchen, aber wie JB Nizet erwähnt, haben wir die DAOs dazu gebracht. Eine wichtige Sache beim Autowiren der DAOs ist, dass Spring sie standardmäßig bei Singletons verwaltet, so dass Sie nicht viel Objekte erstellen können. Ihr Codebeispiel erstellt jedes Mal, wenn Sie ein bestimmtes DAO verwenden müssen, eine neue Kopie jedes DAO. Dies sollte nicht erforderlich sein. – Marvo

+0

@JB Nizet: Wir verwenden DI viel, nur nicht für die DAOs. Ich bin nicht auf diese Methode gekommen, aber ich habe eine Chance, sie zu überarbeiten, daher die Frage. –

Antwort

5

Ich werde alle DAO s als Spring verwaltete Komponenten haben und sie in Dienste für lose Kopplung injizieren. Warum denkst du, dass das Autowiren von Bohnen in einem großen Projekt schlecht ist?

mit Anmerkungen versehen Nur jede DAO Klasse mit @Component und ersetzen MyDao mydao = factory.getmyDao() mit

@Autowired MyDao myDao;

Ich sehe nicht viel Codierung/Konfigurationsaufwand mit sich.

0

Wenn Sie zu viele DAOs in 1 Service sollten Sie darüber nachdenken, zu spalten 1 Service in mehr unteren Hebel (feinkörnig) -Dienste

1

Gute Frage.

Ich denke, das ist sehr schade, dass Sie begonnen haben, DAOFactory zu verwenden. Der Frühling ist eine super flexible Fabrik, also verstehe ich wirklich nicht, warum du eine andere brauchst. Das Autowiren im Frühjahr hat viele Vorteile und erfordert keine Schnittstellen, sodass Sie leicht auf die Feder zugreifen können, um auf DAOs zuzugreifen. IMHO reduziert es nicht und verbessert die Sichtbarkeit für andere Entwickler.

Außerdem, wenn Sie über Refactoring von DAO Schicht denken Sie einen Blick auf GenericDAO von Google Code nehmen: http://code.google.com/p/hibernate-generic-dao/

Ich hatte eine sehr gute Erfahrung mit dieser Bibliothek. Es spart Ihnen Zeit. Sie brauchen eigentlich nicht viele DAOs. Sie benötigen genau ein DAO. Sie können das generische DAO natürlich von Google Code umschließen und Ihre anwendungsspezifische Terminologie und Funktionalität hinzufügen. Aber fügen Sie dort keinen spezifischen Code hinzu. Der Entitätsspezifische Code sollte sich auf der Serviceebene befinden. Kein fragiler HQL, keine Kopplung mit Ruhezustand, wenn Sie die Hibernate-Kriterien-API verwenden. Diese Bibliothek unterstützt sowohl Hibernate als auch JPA und ihre API ist sehr einfach und stark.

3

Ich habe bisher ein paar verschiedene Ansätze mit meinen Projekten verfolgt und habe mich nicht wirklich darauf festgelegt, was "das Beste" ist. Und vielleicht gibt es kein "Bestes", aber vielleicht ein "Bestes für Ihre Bedürfnisse".

Zuerst ging ich mit einer Basisdienstklasse.

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

Dann in meinen Dienstklassen, kann ich einfach

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

Dies funktioniert, schreiben und es hält meine Dienste ordentlich aus allen autowiring und Zugriffsklassen für das dao Instanzvariablen. Problem ist, ich habe jetzt eine Kopie dieser Basisklasse in jedem meiner Dienste, die ehrlich gesagt, meh, nicht so groß von einem Deal. Aber es produziert auch einen Code-Geruch, weil es keine Komposition über Vererbung verwendet, wo ein Grund für DI im Wesentlichen darin besteht, die Komposition zu fördern.

Ein Mitarbeiter schlug eine Fabrik wie Ihre vor und nannte sie ServiceProvider. Wir bringen dies in unsere Dienste ein.

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

Dann haben wir etwas wie das, was Sie haben:

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

Und das ist verdammt hässlich und wirklich nicht selbst Klarheit eignet. Also haben wir versucht, nur die Instanz des Anbieters zu verwenden und sie so kurz und knapp wie sp zu benennen. Dann erhalten wir

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

Und wieder funktioniert es. Und es ist wahrscheinlich ein besseres Design. Und wir bringen die DAOs nur an einen Ort und nicht in jeden Dienst, auch wenn das eigentlich kein Problem ist. Aber es macht mich besser fühlen, obwohl Ich fühle mich besser ist kein Projekt Anforderung (aber nicht cha denke, es sollte sein?)

Ich habe gedacht, wir würden die beiden kombinieren. Wir würden BaseService ändern, um den ServiceProvider automatisch zu starten, und dann die hässlichen Aufrufe umbrechen.

public abstract BaseService { 
    @Autowired ServiceProvider serviceProvider; 

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

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

Sorgt für schönere Stenografie in meine Dienste, mich nicht erfordert jedes DAO in jeden Dienst autowire, die nur klobig wird, meiner Meinung nach, aber auch nicht eine Kopie aller in jeder dieser Referenzen hat Service, der eine absolut lächerliche Angelegenheit ist.

Das Problem, das ich habe, besteht darin, Code im Debugger zu durchlaufen. Das Ein- und Aussteigen von jedem dieser getWhateverDAO() - Aufrufe ist mühsam, und das Hinzufügen eines möglichen Schrittes durch getServiceProvider() hilft auch nicht.

Aber das ist, wo ich mit diesem Problem bin. Ehrlich gesagt denke ich, dass ich so viel Zeit damit verbringe, darüber nachzudenken, weil es eine großartige Möglichkeit ist, all die wirklich harten Probleme zu vermeiden, die unsere Anwendung aufwirft.

0

Wenn Sie nicht wollen, Ihre DAO-Klassen oder Anmerkungen wie @Value sie verschmutzen haben Konfiguration mit Anmerkungen versehen, sehe ich zwei Möglichkeiten:

1.Erstellen Sie eine @Configuration mit 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); 
    } 
} 

Dann ein @Autowired Feld für die DAO erstellen Sie benötigen:

@Autowired 
private FooDao fooDao; 

2. eine DAO Fabrik erstellen @Component

Nützlich, wenn Sie brauchen um etwas zu säubern, wenn die DAOs zerstört werden.

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

Dann ein @Autowired Feld für die Fabrik in die Klassen erstellen Sie benötigen DAOs:

@Autowired 
private DaoFactory daoFactory; 

Und verwenden Sie es als:

daoFactory.barDao().findAll();