Forenkle DAO med Spring og Java Generics

1. Oversigt

Denne artikel vil fokusere på forenkling af DAO-laget ved at bruge et enkelt, genereret dataadgangsobjekt til alle enheder i systemet, hvilket vil resultere i elegant datatilgang uden unødvendig rod eller ordlyd.

Vi bygger videre på den abstrakte DAO-klasse, som vi så i vores forrige artikel om forår og dvale, og tilføj generisk support.

2. Hibernate og JPA DAO'er

De fleste produktionskodebaser har en slags DAO-lag. Normalt spænder implementeringen fra flere klasser uden abstrakt basisklasse til en slags genereret klasse. En ting er dog konsekvent - der er altid mere end en. Mest sandsynligt er der en til en relation mellem DAO'erne og enhederne i systemet.

Afhængig af niveauet af generiske involverede kan de faktiske implementeringer også variere fra stærkt duplikeret kode til næsten tom, hvor størstedelen af ​​logikken er grupperet i en base-abstrakt klasse.

Disse multiple implementeringer kan normalt erstattes af en enkelt parametriseret DAO. Vi kan implementere dette, så ingen funktionalitet går tabt ved at drage fuld fordel af den type sikkerhed, der leveres af Java Generics.

Vi viser næste to implementeringer af dette koncept, den ene til et dvale-centreret persistenslag og den anden med fokus på JPA. Disse implementeringer er på ingen måde komplette, men vi kan nemt tilføje flere yderligere dataadgangsmetoder er inkluderet.

2.1. Den abstrakte dvale DAO

Lad os tage et hurtigt kig på AbstraktDvaleDao klasse:

offentlig abstrakt klasse AbstractHibernateDao {privat klasse clazz; @Autowired SessionFactory sessionFactory; public void setClazz (Class clazzToSet) {this.clazz = clazzToSet; } offentlig T findOne (lang id) {return (T) getCurrentSession (). get (clazz, id); } offentlig liste findAll () {returner getCurrentSession (). createQuery ("fra" + clazz.getName ()). liste (); } offentlig T opret (T-enhed) {getCurrentSession (). saveOrUpdate (enhed); returret } offentlig T-opdatering (T-enhed) {return (T) getCurrentSession (). fusion (enhed); } offentlig ugyldig sletning (T-enhed) {getCurrentSession (). sletning (enhed); } public void deleteById (long entityId) {T entity = findOne (entityId); slet (enhed); } beskyttet Session getCurrentSession () {return sessionFactory.getCurrentSession (); }}

Dette er en abstrakt klasse med flere dataadgangsmetoder, der bruger SessionFactory til manipulation af enheder.

2.2. Den generiske dvale DAO

Nu hvor vi har den abstrakte DAO-klasse, kan vi udvide den kun én gang. Den generiske DAO-implementering bliver den eneste implementering vi behøver:

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

Først, bemærk, at den generiske implementering i sig selv er parametreret, der giver klienten mulighed for at vælge den korrekte parameter fra sag til sag. Dette vil betyde, at kunderne får alle fordelene ved typesikkerhed uden at skulle oprette flere artefakter for hver enhed.

For det andet bemærk det prototype omfanget af denne generiske DAO implementering. Brug af dette omfang betyder, at Spring-containeren opretter en ny forekomst af DAO, hver gang den bliver anmodet om (inklusive ved automatisk ledningsføring). Det giver en tjeneste mulighed for at bruge flere DAO'er med forskellige parametre for forskellige enheder efter behov.

Årsagen til, at dette omfang er så vigtigt, skyldes, hvordan Spring initialiserer bønner i beholderen. At lade den generiske DAO være uden et omfang ville betyde at bruge standard singleton-omfanget, hvilket vil føre til en enkelt forekomst af DAO, der bor i containeren. Det ville naturligvis være meget begrænsende for enhver form for mere komplekst scenario.

Det IGenericDao er simpelthen en grænseflade til alle DAO-metoder, så vi kan indsprøjte den implementering, vi har brug for:

offentlig grænseflade IGenericDao {T findOne (sidste lange id); Liste findAll (); ugyldig oprettelse (endelig T-enhed); T-opdatering (endelig T-enhed); ugyldig sletning (endelig T-enhed); ugyldig deleteById (endelig lang enhedId); }

2.3. Den abstrakte JPA DAO

Det AbstraktJpaDao ligner meget AbstraktDvaleDao:

offentlig abstrakt klasse AbstractJpaDao {privat klasseclazz; @PersistenceContext EntityManager entityManager; public void setClazz (Class clazzToSet) {this.clazz = clazzToSet; } offentlig T findOne (lang 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 opdatering (T-enhed) {entityManager.merge (enhed); } offentlig tomrums sletning (T-enhed) {entityManager.remove (enhed); } public void deleteById (Long entityId) {T entity = getById (entityId); slet (enhed); }}

Svarende til Hibernate DAO-implementeringen bruger vi Java Persistence API direkte uden at stole på det forældede forår JpaTemplate.

2.4. Den generiske JPA DAO

Svarende til implementeringen af ​​dvale er JPA Data Access Object ligeledes ligetil:

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

3. Injektion af denne DAO

Vi har nu en enkelt DAO-grænseflade, vi kan injicere. Vi skal også specificere Klasse:

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

Forår autowires den nye DAO-instans ved hjælp af setterinjektion så implementeringen kan tilpasses med Klasse objekt. Efter dette punkt er DAO fuldt parametriseret og klar til brug af tjenesten.

Der er selvfølgelig andre måder, hvorpå klassen kan specificeres til DAO - via refleksion eller endda i XML. Min præference er over denne enklere løsning på grund af den forbedrede læsbarhed og gennemsigtighed sammenlignet med brug af refleksion.

4. Konklusion

Denne artikel diskuterede forenkling af Data Access Layer ved at levere en enkelt genanvendelig implementering af en generisk DAO. Vi viste implementeringen i både et dvale- og et JPA-baseret miljø. Resultatet er et strømlinet persistenslag uden unødvendig rod.

For en trinvis introduktion til opsætning af Spring-kontekst ved hjælp af Java-baseret konfiguration og den grundlæggende Maven pom til projektet, se denne artikel.

Endelig kan koden til denne artikel findes i GitHub-projektet.


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