Forenkle DAO med Spring og Java Generics

1. Oversikt

Denne artikkelen vil fokusere på forenkle DAO-laget ved å bruke et enkelt, generert dataadgangsobjekt for alle enheter i systemet, noe som vil resultere i elegant datatilgang uten unødvendig rot eller ordlyd.

Vi vil bygge videre på den abstrakte DAO-klassen vi så i vår forrige artikkel om vår og dvalemodus, og legge til generisk støtte.

2. Hibernate og JPA DAOs

De fleste produksjonskodebaser har en slags DAO-lag. Vanligvis varierer implementeringen fra flere klasser uten abstrakt basisklasse til en slags generert klasse. Imidlertid er en ting konsekvent - det er det alltid mer enn en. Mest sannsynlig er det et forhold mellom DAO og enhetene i systemet.

Avhengig av nivået på generiske stoffer som er involvert, kan de faktiske implementeringene også variere fra sterkt duplisert kode til nesten tom, med hovedtyngden av logikken gruppert i en base abstrakt klasse.

Disse flere implementeringene kan vanligvis erstattes av en enkelt parametrisert DAO. Vi kan implementere dette slik at ingen funksjonalitet går tapt ved å dra full nytte av typen sikkerhet gitt av Java Generics.

Vi viser neste to implementeringer av dette konseptet, en for et dvale-sentrisk utholdenhetslag og den andre med fokus på JPA. Disse implementeringene er på ingen måte fullstendige, men vi kan enkelt legge til flere ekstra datatilgangsmetoder er inkludert.

2.1. The Abstract Hibernate DAO

La oss ta en rask titt på AbstraktHibernateDao klasse:

offentlig abstrakt klasse AbstractHibernateDao {private Class clazz; @Autowired SessionFactory sessionFactory; public void setClazz (Class clazzToSet) {this.clazz = clazzToSet; } public T findOne (long id) {return (T) getCurrentSession (). get (clazz, id); } public List findAll () {return getCurrentSession (). createQuery ("from" + clazz.getName ()). list (); } offentlig T opprett (T-enhet) {getCurrentSession (). saveOrUpdate (enhet); retur enhet; } offentlig T-oppdatering (T-enhet) {retur (T) getCurrentSession (). slå sammen (enhet); } public void delete (T entity) {getCurrentSession (). delete (entity); } offentlig tomrom deleteById (long entityId) {T entity = findOne (entityId); slett (enhet); } beskyttet Session getCurrentSession () {return sessionFactory.getCurrentSession (); }}

Dette er en abstrakt klasse med flere datatilgangsmetoder som bruker SessionFactory for å manipulere enheter.

2.2. The Generic Hibernate DAO

Nå som vi har den abstrakte DAO-klassen, kan vi utvide den bare en gang. Den generiske DAO-implementeringen blir den eneste implementeringen vi trenger:

@Repository @Scope (BeanDefinition.SCOPE_PROTOTYPE) offentlig klasse GenericHibernateDao utvider AbstractHibernateDao implementerer IGenericDao {//}

Først, Vær oppmerksom på at den generiske implementeringen i seg selv er parametrisert, slik at klienten kan velge riktig parameter fra sak til sak. Dette vil bety at kundene får alle fordelene med typesikkerhet uten å måtte lage flere gjenstander for hver enhet.

For det andre, legg merke til det prototypen på denne generiske DAO-implementeringen. Å bruke dette omfanget betyr at Spring-containeren vil opprette en ny forekomst av DAO hver gang den blir bedt om (inkludert ved automatisk kabling). Det vil tillate at en tjeneste bruker flere DAOer med forskjellige parametere for forskjellige enheter, etter behov.

Årsaken til at dette omfanget er så viktig, skyldes måten Spring initialiserer bønner i beholderen. Å la den generiske DAO uten omfang vil bety å bruke standard singleton-omfanget, noe som vil føre til en enkelt forekomst av DAO som bor i containeren. Det ville åpenbart være veldig begrensende for alle slags mer komplekse scenarier.

De IGenericDao er rett og slett et grensesnitt for alle DAO-metodene slik at vi kan injisere implementeringen vi trenger:

offentlig grensesnitt IGenericDao {T findOne (endelig lang ID); Liste findAll (); void create (final T entity); T-oppdatering (endelig T-enhet); ugyldig sletting (endelig T-enhet); ugyldig deleteById (endelig lang enhetId); }

2.3. Den abstrakte JPA DAO

De SammendragJpaDao er veldig lik AbstraktHibernateDao:

offentlig abstrakt klasse AbstractJpaDao {private Class clazz; @PersistenceContext EntityManager entityManager; public void setClazz (Class clazzToSet) {this.clazz = clazzToSet; } public T findOne (Long id) {return entityManager.find (clazz, id); } offentlig liste findAll () {return entityManager.createQuery ("fra" + clazz.getName ()) .getResultList (); } public void save (T entity) {entityManager.persist (entity); } offentlig ugyldig oppdatering (T-enhet) {entityManager.merge (enhet); } offentlig ugyldig sletting (T-enhet) {entityManager.remove (enhet); } offentlig ugyldig deleteById (Long entityId) {T entity = getById (entityId); slett (enhet); }}

I likhet med Hibernate DAO-implementeringen bruker vi Java Persistence API direkte, uten å stole på den nå avviklede våren JpaTemplate.

2.4. Den generiske JPA DAO

I likhet med dvalemodus-implementeringen er JPA Data Access Object også grei:

@Repository @Scope (BeanDefinition.SCOPE_PROTOTYPE) offentlig klasse GenericJpaDao utvider AbstractJpaDao implementerer IGenericDao {//}

3. Injisere denne DAO

Vi har nå et enkelt DAO-grensesnitt vi kan injisere. Vi må også spesifisere Klasse:

@ Service-klasse FooService implementerer IFooService {IGenericDao dao; @Autowired public void setDao (IGenericDao daoToSet) {dao = daoToSet; dao.setClazz (Foo.class); } // ...}

Vår autowires den nye DAO-forekomsten ved hjelp av setterinjeksjon slik at implementeringen kan tilpasses med Klasse gjenstand. Etter dette punktet er DAO helt parametrisert og klar til å bli brukt av tjenesten.

Det er selvfølgelig andre måter som klassen kan spesifiseres for DAO - via refleksjon, eller til og med i XML. Min preferanse er mot denne enklere løsningen på grunn av forbedret lesbarhet og gjennomsiktighet sammenlignet med bruk av refleksjon.

4. Konklusjon

Denne artikkelen diskuterte forenkling av datatilgangslaget ved å tilby en enkelt, gjenbrukbar implementering av en generisk DAO. Vi viste implementeringen i både et dvalemodus og et JPA-basert miljø. Resultatet er et strømlinjeformet utholdenhetslag uten unødvendig rot.

For en trinnvis introduksjon om å sette opp vårkonteksten ved hjelp av Java-basert konfigurasjon og den grunnleggende Maven pom for prosjektet, se denne artikkelen.

Til slutt finner du koden for denne artikkelen i GitHub-prosjektet.


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