Pojednostavite DAO pomoću Spring i Java Generics

1. Pregled

Ovaj će se članak usredotočiti na pojednostavljenje sloja DAO korištenjem jedinstvenog, generiranog objekta za pristup podacima za sve entitete u sustavu, što će rezultirati elegantnim pristupom podacima, bez nepotrebne gužve ili više riječi.

Nadogradit ćemo klasu Sažetak DAO koju smo vidjeli u našem prethodnom članku o Proljeću i hibernaciji i dodati generičku podršku.

2. Hibernate i JPA DAO

Većina proizvodnih baza kodova ima neku vrstu DAO sloja. Obično se implementacija kreće od više klasa bez apstraktne osnovne klase do neke generizirane klase. Međutim, jedna stvar je dosljedna - postoji uvijek više od jednog. Najvjerojatnije postoji odnos jedan prema jedan između DAO-a i entiteta u sustavu.

Također, ovisno o razini generičkih podataka koji su uključeni, stvarne implementacije mogu varirati od jako dupliciranog koda do gotovo praznog, a glavnina logike grupirana je u osnovnu apstraktnu klasu.

Te se višestruke implementacije obično mogu zamijeniti jednim parametriziranim DAO. To možemo implementirati tako da se ne izgubi funkcionalnost u potpunosti iskorištavajući sigurnost tipa koju pruža Java Generics.

Sljedeće ćemo prikazati dvije implementacije ovog koncepta, jednu za hibernacijski orijentirani sloj postojanosti, a drugu s fokusom na JPA. Te implementacije nipošto nisu cjelovite, ali možemo lako dodati još dodatnih metoda pristupa podacima.

2.1. Sažetak hibernacije DAO

Pogledajmo na brzinu SažetakHibernateDao razred:

javni sažetak klase AbstractHibernateDao {privatna klasa klazz; @Autowired SessionFactory sessionFactory; javna praznina setClazz (Klasa clazzToSet) {this.clazz = clazzToSet; } javni T findOne (dugi id) {return (T) getCurrentSession (). get (clazz, id); } javni popis findAll () {return getCurrentSession (). createQuery ("from" + clazz.getName ()). list (); } javno T stvaranje (T entitet) {getCurrentSession (). saveOrUpdate (entitet); entitet povratka; } javno ažuriranje T (T entitet) {return (T) getCurrentSession (). merge (entitet); } javno prazno brisanje (T entitet) {getCurrentSession (). delete (entitet); } javna praznina deleteById (long entityId) {T entitet = findOne (entityId); izbrisati (entitet); } zaštićena sesija getCurrentSession () {povratak sessionFactory.getCurrentSession (); }}

Ovo je apstraktna klasa s nekoliko metoda pristupa podacima koja koristi SjednicaTvornica za manipulaciju entitetima.

2.2. Generički zimski san DAO

Sad kad imamo apstraktnu klasu DAO, možemo je proširiti samo jednom. Generička provedba DAO postat će jedina provedba trebamo:

@Repository @Scope (BeanDefinition.SCOPE_PROTOTYPE) javna klasa GenericHibernateDao proširuje AbstractHibernateDao implementira IGenericDao {//}

Prvi, imajte na umu da je generička provedba sama po sebi parametrizirana, omogućujući klijentu da odabere ispravan parametar od slučaja do slučaja. To će značiti da klijenti ostvaruju sve prednosti sigurnosti tipa bez potrebe za stvaranjem višestrukih artefakata za svaki entitet.

Drugo, primijetite prototip opsega ove generičke DAO implementacije. Korištenje ovog opsega znači da će Spring spremnik stvoriti novu instancu DAO-a svaki put kada se zatraži (uključujući pri automatskom ožičenju). To će omogućiti službi da koristi više DAO-a s različitim parametrima za različite entitete, prema potrebi.

Razlog zašto je ovaj opseg toliko važan je način na koji Spring inicijalizira grah u spremniku. Ostaviti generički DAO bez opsega značilo bi koristiti zadani singleton opseg, što bi dovelo do jedne instance DAO-a koji živi u spremniku. To bi očito bilo uglavnom restriktivno za bilo koji složeniji scenarij.

The IGenericDao je jednostavno sučelje za sve DAO metode kako bismo mogli ubrizgati potrebnu implementaciju:

javno sučelje IGenericDao {T findOne (konačni dugi id); Popis findAll (); void create (konačni T entitet); T ažuriranje (konačni T entitet); brisanje praznine (konačni T entitet); void deleteById (konačni dugi entitet id); }

2.3. Sažetak JPA DAO

The SažetakJpaDao je vrlo sličan SažetakHibernateDao:

javni sažetak klase AbstractJpaDao {privatna klasa klazz; @PersistenceContext EntityManager entityManager; javna praznina setClazz (Klasa clazzToSet) {this.clazz = clazzToSet; } public T findOne (Long id) {return entityManager.find (clazz, id); } javni popis findAll () {return entityManager.createQuery ("from" + clazz.getName ()) .getResultList (); } javno spremanje praznine (T entitet) {entityManager.persist (entitet); } javno void ažuriranje (T entitet) {entityManager.merge (entitet); } javno prazno brisanje (T entitet) {entityManager.remove (entitet); } javna praznina deleteById (Long entityId) {T entitet = getById (entityId); izbrisati (entitet); }}

Slično implementaciji Hibernate DAO, mi izravno koristimo Java Persistent API, bez oslanjanja na sada zastarjelo Spring JpaTemplate.

2.4. Generički JPA DAO

Slično implementaciji hibernacije, objekt pristupa JPA podacima također je jednostavan:

@Repository @Scope (BeanDefinition.SCOPE_PROTOTYPE) javna klasa GenericJpaDao proširuje AbstractJpaDao implementira IGenericDao {//}

3. Ubrizgavanje ovog DAO-a

Sada imamo jedno DAO sučelje koje možemo ubrizgati. Također moramo navesti Klasa:

@Service klasa FooService implementira IFooService {IGenericDao dao; @Autowired javna praznina setDao (IGenericDao daoToSet) {dao = daoToSet; dao.setClazz (Foo.class); } // ...}

Proljeće automatski spaja novu DAO instancu pomoću postavljanja ubrizgavanja tako da se izvedba može prilagoditi s Razred objekt. Nakon ove točke, DAO je u potpunosti parametriziran i spreman za upotrebu u usluzi.

Postoje naravno i drugi načini na koje se klasa može odrediti za DAO - refleksijom ili čak u XML-u. Moja je prednost prema ovom jednostavnijem rješenju zbog poboljšane čitljivosti i transparentnosti u usporedbi s korištenjem refleksije.

4. Zaključak

Ovaj je članak raspravljao o pojednostavljenje sloja pristupa podacima pružanjem jedne, višekratne provedbe generičkog DAO-a. Pokazali smo primjenu u hibernaciji i okruženju temeljenom na JPA. Rezultat je pojednostavljeni sloj postojanosti, bez nepotrebne gužve.

Za detaljni uvod o postavljanju proljetnog konteksta pomoću Java konfiguracije i osnovne Maven pom za projekt, pogledajte ovaj članak.

Konačno, kôd ovog članka može se naći u projektu GitHub.


$config[zx-auto] not found$config[zx-overlay] not found