[Spring] Opzetten Data Access Layer

Pagina: 1
Acties:
  • 128 views sinds 30-01-2008
  • Reageer

  • Casteloni
  • Registratie: November 2001
  • Laatst online: 26-03 13:31
Na een tijd met Struts gewerkt te hebben ben ik nu de mogelijkheden van Spring te onderzoeken. Tot nu toe bevalt het me zeer goed. Soms is het een beetje verwarrend dat op configuratie niveau alles een bean is, maar het controller + view gedeelte heb ik er grotendeels in zitten.

Ik ben me nu gaan richten op de laag naar de database toe. Mijn doel is om met zo min mogelijk code en zo schaalbaar mogelijke laag naar de database te bouwen. Ik wil eigenlijk alleen in de spring config willen opgeven wat voor type database ik wil gebruiken. Het voorbeeld wat onder de documentatie van Spring staat voldoet niet helemaal aan mijn eisen.

Als ik het goed begrepen heb zijn er in ieder geval 2 typen objecten nodig: DAO's en POJO's. De DAO klasse praat met de database en retourneerd de data in de vorm van POJO's. Maar, wat is een nette manier om de DAO's aan te spreken?, Ik heb dit gebaseerd op het Data Access Pattern die hieronder is afgebeeld:
Afbeeldingslocatie: http://java.sun.com/blueprints/corej2eepatterns/Patterns/images09/figure09_06.gif
Eigenlijk zou ik die zogenaamde Client het liefst met de interface van de DAO laten praten. De spring configuratie zou moeten bepalen welke implementatie hiervoor gebruikt moet worden.

Het voorbeeld gebruikt zogenaamde 'Managers' voor de communicatie met de DAO's. Deze worden geinstantieerd door een Controller en zijn in feite normale klassen die een collectie van POJO's returned. Zo is er bijv een CustomerManager die een methode getCustomers() of getCustomerById heeft. Is dit gebruikelijk?

Verder zit ik nog een beetje met het afhandelen van transacties. Het is natuurlijk niet wenselijk dat een bepaalde batch ( functionaliteit van de applicatie ) 2 keer wordt uitgevoerd. Ik heb me hier nog niet echt in verdiept, maar als iemand een mooi voorbeeld heeft dan hoor ik het graag :+

Doel van dit topic is om eigenlijk mijn eigen 'probleem' op te lossen maar het is natuurlijk ook heel interessant om hier een discussie te voeren over wat nu de 'mooiste' manier is om dit op te lossen. >:)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

VampireSlayer schreef op maandag 20 februari 2006 @ 20:07:
Na een tijd met Struts gewerkt te hebben ben ik nu de mogelijkheden van Spring te onderzoeken. Tot nu toe bevalt het me zeer goed. Soms is het een beetje verwarrend dat op configuratie niveau alles een bean is, maar het controller + view gedeelte heb ik er grotendeels in zitten.

Ik ben me nu gaan richten op de laag naar de database toe. Mijn doel is om met zo min mogelijk code en zo schaalbaar mogelijke laag naar de database te bouwen.
Wat versta je onder schaalbaar? Schaalbaar qua performance (clusteren?)
Ik wil eigenlijk alleen in de spring config willen opgeven wat voor type database ik wil gebruiken. Het voorbeeld wat onder de documentatie van Spring staat voldoet niet helemaal aan mijn eisen.
Het is geen probleem om de datasource in Spring te configureren. Voor mij is het dan ook 1 regel aanpassen, en dan spreek je een andere db aan. Maar volgens mij is dit niet helemaal wat je bedoelt.
Als ik het goed begrepen heb zijn er in ieder geval 2 typen objecten nodig: DAO's en POJO's. De DAO klasse praat met de database en retourneerd de data in de vorm van POJO's.
Yes. En je plaatst er ook pojo`s in. Dus employeeDao.delete(persoon);
Maar, wat is een nette manier om de DAO's aan te spreken?, Ik heb dit gebaseerd op het Data Access Pattern die hieronder is afgebeeld:
[afbeelding]
Eigenlijk zou ik die zogenaamde Client het liefst met de interface van de DAO laten praten. De spring configuratie zou moeten bepalen welke implementatie hiervoor gebruikt moet worden.
Over het algemeen is het niet altijd nodig om database specifieke dao`s te maken. Meestal maak je gebruik van techniek specifieke dao`s. Bv Hibernate, JDO, Ibatis.. etc... (mijn favoriet is Hibernate).

Je kunt dit als volgt doen:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface EmployeeDao{
    void save(Employee e);
}

class HibernateEmployeeDao implements EmployeeDao{
    void save(Employee e){...}
}

interface EmployeeManager{
  void fire(Employee e);
}

class EmployeeManagerImpl implements EmployeeManager{
   private EmployeeDao dao;

   public EmployeeManagerImpl(EmployeeDao dao){
      this.dao = dao;
   }

   public void fire(Employee e){
      e.setFired(true);
      dao.save(e);
   }
}


En dit kun je als volgt oplijmen in Spring:

code:
1
2
3
4
5
6
7
<bean id="employeeDao"
          class="HibernateEmployeeDao"/>

<bean id="employeeManager"
          class="EmployeeManagerImpl">
    <constructor ref="employeeDao"/>
</bean>
Het voorbeeld gebruikt zogenaamde 'Managers' voor de communicatie met de DAO's. Deze worden geinstantieerd door een Controller en zijn in feite normale klassen die een collectie van POJO's returned.
Managers worden niet genstantieerd door de controller. Ze worden gewoon aangemaakt in de applicatie context (net zoals iedere andere bean).

Als een controller een manager nodig is, kan je het volgende doen:
code:
1
2
3
4
<bean id="employeeController"
          class="EmployeeController">
    <constructor ref="employeeManager"/>
</bean>
Zo is er bijv een CustomerManager die een methode getCustomers() of getCustomerById heeft. Is dit gebruikelijk?
Yep.
Verder zit ik nog een beetje met het afhandelen van transacties. Het is natuurlijk niet wenselijk dat een bepaalde batch ( functionaliteit van de applicatie ) 2 keer wordt uitgevoerd. Ik heb me hier nog niet echt in verdiept, maar als iemand een mooi voorbeeld heeft dan hoor ik het graag :+
Het transactie topic in de Spring documentatie is heel aardig als naslag werk, maar je kunt beter een goed boek aanschaffen over Spring (Pro Spring bv) als je ermee wilt beginnen. Er komen nogal wat complexe technieken in voor (ao AOP), dus in het begin kan het nogal overdonderend zijn. Maar na een tijdje (vooral als je Spring-AOP meester bent) dan is het kinderspel.

Ik ben trouwens bezig met een blog oa over transacties/locking/isolationlevels binnen databases. Ik hoop dat deze week te kunnen posten. Binnenkort komt er ook een blog over concurrency binnen Spring applicaties (en dan vooral mbt domain objecten, dao`s, managers, database, en de gui laag).
Doel van dit topic is om eigenlijk mijn eigen 'probleem' op te lossen maar het is natuurlijk ook heel interessant om hier een discussie te voeren over wat nu de 'mooiste' manier is om dit op te lossen. >:)
Discussies voeren is altijd goed. Ik hang zelf redelijk veel op het Spring forum rond, en daar zijn veel mensen die er veel kaas van hebben gegeten. Je kunt het daar ook een keer proberen.. (veel mensen zijn tegen dezelfde problemen aangelopen als jij, en op GoT kom je dat soort mensen toch minder tegen).

[ Voor 29% gewijzigd door Alarmnummer op 20-02-2006 20:36 ]


  • KurtDB
  • Registratie: Juni 2004
  • Laatst online: 09-02 20:28
De manier dat wij 't op het werk meestal aanpakken is dat we tussen de controller en de DAO nog 2 lagen hebben. Dit zijn de business delegate (flexibiliteit moest er na verloop van tijd plots gebruik gemaakt moeten worden van EJB's) en de session facade. Hierdoor krijg je 'n deel flexibiliteit omdat je in je session facade je hele transactie logica kan gaan regelen en je je implementaties van de verschillende lagen zonder problemen kan wisselen.

Gebruik alvast ook de templates die spring je aanbiedt voor de verschillende DAO-strategiën. Die zorgen er immers voor dat je 'n heleboel boilerplate code vermijdt. Een verder voordeel is dat de exceptions die je rdbms gooit automagisch vertaald worden naar een iets logischere uitleg.

Enige probleempje dat ik zie is dat je verwacht dat spring zelf gaat bepalen welke bean hij in 'n bepaalde situatie nodig gaat hebben. Om je code wat proper te houden ga je als parameter van 'n methode 'n interface gebruiken, maar jij moet in je application context gaan aangeven welke implementatie hij moet "injecten".

  • Casteloni
  • Registratie: November 2001
  • Laatst online: 26-03 13:31
Alarmnummer schreef op maandag 20 februari 2006 @ 20:26:
[...]
Wat versta je onder schaalbaar? Schaalbaar qua performance (clusteren?)
Meer qua grootte van de applicatie. FO is nu vastgelegd maar we weten al bijna zeker dat er meer aan gaat komen.
[...]
interface EmployeeManager{
void fire(Employee e);
}
[...]
[/code]
Waarom maak je een interface voor de manager klasse?
[..stuk over transacties...]
Dan ga ik dat tzt maar eens lezen ;), eerst de basics opzetten en dan verder opbouwen. Applicatie is nu (nog) niet heel groot.

Het principe 'lijmen' is me nu ook duidelijk geworden. In feite zorgt spring er voor dat bepaalde objecten geinstantieerd worden zonder dat je er zelf naar om hoeft te kijken. Bijvoorbeeld via het constructor element kan je een andere 'bean' eraan lijmen.

Morgen ga ik hier maar mee aan de slag! thx _/-\o_

  • Bbfreak
  • Registratie: September 2002
  • Laatst online: 04-02 10:03
Als je zelf nog niet veel ervaring hebt met Spring raad ik je aan om naar Equinox te kijken. Dit is een lichte versie van AppFuse.
Een applicatie die door jou gewenste functionaliteit out of the box bevat.
Je kunt hier goed zien hoe ze hier met DAO + Managers werken. Schitterende opzet en enorm flexibel.
Mijn UML: Afbeeldingslocatie: http://www.coenm.nl/UML.jpg
Dit is wel met SpringMVC geimplementeerd. Ik hoop niet voor jou dat er fouten inzitten.
Anders moet iemand anders me daar maar op wijzen. :D

Twitter @cmeerbeek / Halo Waypoint Profile


  • Cuball
  • Registratie: Mei 2002
  • Laatst online: 03-04 10:15
zoals Alarmnummer zei zou ik het boek Pro Spring aanschaffen, het leest leuk en het antwoord op veel vragen die je in het begin tegenkomt. Het boek is niet enkel voor de beginnende Springer maar je vindt er ook wat meer geavanceerde topics terug, dus zeker een aandrader!

"Live as if you were to die tomorrow. Learn as if you were to live forever"


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

VampireSlayer schreef op maandag 20 februari 2006 @ 20:54:
[...]
Waarom maak je een interface voor de manager klasse?
Testdoeleinden voornamelijk.
Het principe 'lijmen' is me nu ook duidelijk geworden. In feite zorgt spring er voor dat bepaalde objecten geinstantieerd worden zonder dat je er zelf naar om hoeft te kijken. Bijvoorbeeld via het constructor element kan je een andere 'bean' eraan lijmen.
Lijmen is te gek, je verliest zo veel ruis code en je hebt een paar bestanden waarin je je hele applicatie in elkaar lijmt.
Morgen ga ik hier maar mee aan de slag! thx _/-\o_
succes.

  • Casteloni
  • Registratie: November 2001
  • Laatst online: 26-03 13:31
Ik heb nu al een aardig stuk geimplementeerd en ik ben onder de indruk van het gemak waar het mee ging. Heb er zeker een goed gevoel over. Nu ben ik mijn model iets aan het uitbreiden, mijn Customer heeft nu bijvoorbeeld meerdere Order objecten. Nu wil ik eigenlijk kunnen zeggen: customer.getOrders() waar customer dan mijn POJO is.

Dit zou moeten betekenen dat ik bij het instantieren van mijn CustomerPOJO ik een collectie van OrderPOJO's meegeef. Dit kan ik natuurlijk goed door mijn CustomerManager laten afhandelen.

Nu zit ik er een beetje mee dat die Orders bijvoorbeeld niet altijd nodig zijn ( stel je toont alleen een lijst van customers). Wat ik dus eigenlijk wil is dat de getOrders methode wel een collectie returned, maar pas als ik deze ook echt aanroep. Hoe is dit netjes op te lossen?

Ik dacht zelf aan het volgende: In mijn CustomerPOJO een referentie houden naar mijn CustomerDAO. Als dan customerPOJO.getOrders() wordt aangeroepen automatisch customerDAO.getOrders() aanroepen?

Ik ga ook maar eens zoeken naar een goed boek voor Spring ;-)

  • Cuball
  • Registratie: Mei 2002
  • Laatst online: 03-04 10:15
Dit is een hibernate topic,

je moet ervoor zorgen dat de objecten die in je collectie lazy geladen worden, dit doe je door in de metadata van je Order class aan te geven dat deze lazy geladen moet worden.

Hibernate zorgt er dan voor dat van zodra je deze collectie aanroept (in feite doe je dit op een proxy object) pas dan de databank gaat aanspreken en deze orders ophalen.

"Live as if you were to die tomorrow. Learn as if you were to live forever"


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

VampireSlayer schreef op woensdag 22 februari 2006 @ 12:04:
Ik heb nu al een aardig stuk geimplementeerd en ik ben onder de indruk van het gemak waar het mee ging. Heb er zeker een goed gevoel over. Nu ben ik mijn model iets aan het uitbreiden, mijn Customer heeft nu bijvoorbeeld meerdere Order objecten. Nu wil ik eigenlijk kunnen zeggen: customer.getOrders() waar customer dan mijn POJO is.
Tip:
probeer niet iedere relatie die in je model aanwezig is, in java te implementeren. Ik prefereer in veel gevallen een dao call.

dus een:
Set<Order> orders = orderDao.findByCustomer(customer);
ipv een
Set<Order> orders = customer.getOrders();
Nu zit ik er een beetje mee dat die Orders bijvoorbeeld niet altijd nodig zijn ( stel je toont alleen een lijst van customers). Wat ik dus eigenlijk wil is dat de getOrders methode wel een collectie returned, maar pas als ik deze ook echt aanroep. Hoe is dit netjes op te lossen?
1) lazy loading (check hibernate bv)
2) gewoon een dao aanspreken als je het nodig bent.
Ik dacht zelf aan het volgende: In mijn CustomerPOJO een referentie houden naar mijn CustomerDAO. Als dan customerPOJO.getOrders() wordt aangeroepen automatisch customerDAO.getOrders() aanroepen?
Goed idee, alleen slecht te realiseren in Spring 1 omdat Spring 1 niet beschikt over de functionaliteit om dependencies (jouw customerDao/orderDao) te injecteren in domain objects. Vanaf Spring 2 zal dit wel mogelijk zijn.
Ik ga ook maar eens zoeken naar een goed boek voor Spring ;-)
Spring Pro is mijn favoriet.

  • Cuball
  • Registratie: Mei 2002
  • Laatst online: 03-04 10:15
Alarmnummer schreef op woensdag 22 februari 2006 @ 12:29:
[...]

Tip:
probeer niet iedere relatie die in je model aanwezig is, in java te implementeren. Ik prefereer in veel gevallen een dao call.

dus een:
Set<Order> orders = orderDao.findByCustomer(customer);
ipv een
Set<Order> orders = customer.getOrders();
Wat ik me heb afgevraagd met bovenstaande code, is het dan zo dat je bv een Order klasse hebt (domein object met gegevens van orders en ipv van daar een Collectie in te plaatsten (en deze op te geven in een hibernate mapping) met Items heb je nu een dao call om deze Items op te halen?

Of zie ik het verkeerd ? Maar als je dan bv Order objecten aanmaakt, geef je die dan allemaal een itemDao mee ?

kan je wat toelichten ?

"Live as if you were to die tomorrow. Learn as if you were to live forever"


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Cuball schreef op vrijdag 24 februari 2006 @ 08:20:
[...]
Wat ik me heb afgevraagd met bovenstaande code, is het dan zo dat je bv een Order klasse hebt (domein object met gegevens van orders en ipv van daar een Collectie in te plaatsten (en deze op te geven in een hibernate mapping) met Items heb je nu een dao call om deze Items op te halen?
Daar noem je net weer een leuke. Objecten die alleen kunnen bestaan in de context van een ander object (parent), die laat ik altijd via die parent uitlezen en bewaren. Het zal niet vaak voorkomen dat je alleen in de OrderRegel bent geinteresseerd (dus jouw 2e oplossing gebruik ik voor dit type objecten).

Dus mijn Order heeft wel een collectie met OrderRegels en ik maak dus geen dao voor de OrderRegels. Als ik OrderDao.save(Order) doe, dan trekt hij automatisch de OrderRegels ook mee de db in (dit is afhankelijk van je cascade settings bij de collectie). En als ik een OrderDao.load(id) doe dan krijg ik de Order inclusief zijn OrderRegels terug.

Zie dit voor meer informatie.

[ Voor 8% gewijzigd door Alarmnummer op 24-02-2006 09:00 ]


  • Cuball
  • Registratie: Mei 2002
  • Laatst online: 03-04 10:15
Alarmnummer schreef op vrijdag 24 februari 2006 @ 08:52:
[...]

Dus mijn Order heeft wel een collectie met OrderRegels en ik maak dus geen dao voor de OrderRegels. Als ik OrderDao.save(Order) doe, dan trekt hij automatisch de OrderRegels ook mee de db in (dit is afhankelijk van je cascade settings bij de collectie). Zie dit voor meer informatie.
ja cascade settings ben ik bekend mee, maar Order - Item relatie is inderdaad iets die moeilijk zonder elkaar kunnen.

Maar misschien is mijn vraag beetje verkeerd gesteld, wij gebruiken nu om bv een Customer voor te stellen simpele java (POJO) objecten met wat getters en setters en wat methodes om het ons gemakkelijker te maken. In een Customer object hebben we dus nooit db calls, een Customer komt ook overeen met een mapping bv uit Hibernate. Ik vroeg me dan meer af of je dan in zo'n Customer effectief een db call doet? Customer, Order enzo zijn bij ons meer DTO objecten die uit de db laag komen en waar nooit geen db calls meer uitgevoerd worden.

Is dit niet de juiste aanpak ?

"Live as if you were to die tomorrow. Learn as if you were to live forever"

Pagina: 1