Tavaszi egyedi kommentár a jobb DAO-hoz

1. Áttekintés

Ebben az oktatóanyagban megvalósítjuk egyedi tavaszi kommentár bab-utómunkálóval.

Tehát hogyan segít ez? Egyszerűen fogalmazva - ugyanazt a babot újra felhasználhatjuk, ahelyett, hogy több, hasonló típusú babot kellene létrehoznunk.

A DAO megvalósításához ezt egy egyszerű projektben tesszük meg - mindegyiket lecseréljük egyetlen, rugalmasra GenericDao.

2. Maven

Szükségünk van rugómag, tavasz-aop, és tavasz-kontextus-támogatás JAR-ok, hogy ez működjön. Csak kijelenthetjük tavasz-kontextus-támogatás miénkben pom.xml.

 org.springframework tavaszi kontextus-támogatás 5.2.2.KÖZLEMÉNY 

Ha a Spring függőség újabb verziójára szeretne menni, nézze meg a maven tárházat.

3. Új általános DAO

A legtöbb tavaszi / JPA / hibernált megvalósítás a standard DAO-t használja - általában minden entitáshoz egyet.

Ezt a megoldást lecseréljük a-ra GenericDao; Helyette egy egyedi annotációs processzort írunk és ezt használjuk GenericDao végrehajtás:

3.1. Általános DAO

public class GenericDao {private Class entityClass; public GenericDao (Class entityClass) {this.entityClass = entitásosztály. } public List findAll () {// ...} public Opcionális persist (E toPersist) {// ...}} 

Valóságos helyzetben természetesen be kell kapcsolnia a PersistenceContext-et, és valóban meg kell adnia ezeknek a módszereknek a megvalósítását. Egyelőre - ezt a lehető legegyszerűbbé tesszük.

Most létrehozhatunk kommentárokat az egyedi injekciókhoz.

3.2. Adat hozzáférés

@Retention (RetentionPolicy.RUNTIME) @Cél ({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) @Documented public @interface DataAccess {Class entitás (); }

A fenti feljegyzéssel fogjuk beadni a GenericDao alábbiak szerint:

@DataAccess (entitás = Személy.osztály) privát GenericDao personDao;

Talán néhányan azt kérdezik tőled: „Hogyan ismeri fel a tavaszunkat a tavasz? Adat hozzáférés annotáció? ”. Nem - alapértelmezés szerint nem.

De mondhatnánk Springnek, hogy ismerje fel a jegyzetet egy szokáson keresztül BeanPostProcessor - ezt hajtsuk végre legközelebb.

3.3. DataAccessAnnotationProcessor

@Component public class DataAccessAnnotationProcessor implementálja a BeanPostProcessor {private ConfigurableListableBeanFactory configurableBeanFactory; @Autowired public DataAccessAnnotationProcessor (ConfigurableListableBeanFactory beanFactory) {this.configurableBeanFactory = beanFactory; } @Orride public Object postProcessBeforeInitialization (Object bean, String beanName) dobja a BeansException {this.scanDataAccessAnnotation (bean, beanName); visszatérő bab; } @Orride public Object postProcessAfterInitialization (Object bean, String beanName) dobja a BeansException {return bean; } protected void scanDataAccessAnnotation (Object bean, String beanName) {this.configureFieldInjection (bab); } private void configureFieldInjection (Object bean) {Osztály kezeltBeanClass = bean.getClass (); FieldCallback fieldCallback = új DataAccessFieldCallback (konfigurálhatóBeanFactory, bab); ReflectionUtils.doWithFields (managedBeanClass, fieldCallback); }} 

Következő - itt van a DataAccessFieldCallback most használtuk:

3.4. DataAccessFieldCallback

a DataAccessFieldCallback osztály a FieldCallback {private static Logger logger = LoggerFactory.getLogger (DataAccessFieldCallback.class); privát statikus int AUTOWIRE_MODE = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; privát statikus karakterlánc ERROR_ENTITY_VALUE_NOT_SAME = "@DataAccess (entitás)" + "értéknek ugyanazzal a típussal kell rendelkeznie, mint az injektált általános típus."; privát statikus karakterlánc WARN_NON_GENERIC_VALUE = "@DataAccess kommentár" + "-t rendelt a nyers (nem általános) deklarációhoz. Ez kevésbé kódbiztonságossá teszi a kódot."; privát statikus karakterlánc ERROR_CREATE_INSTANCE = "Nem lehet létrehozni a" + "típusú" {} "példányt, vagy a példány létrehozása nem sikerült, mert: {}"; privát ConfigurableListableBeanFactory configurableBeanFactory; magánobjektum bab; public DataAccessFieldCallback (ConfigurableListableBeanFactory bf, Object bean) {configurableBeanFactory = bf; ez.bab = bab; } @Orride public void doWith (Field field) az IllegalArgumentException, az IllegalAccessException elemet dobja {if (! Field.isAnnotationPresent (DataAccess.class)) {return; } ReflectionUtils.makeAccessible (mező); Típus fieldGenericType = field.getGenericType (); // Ebben a példában kapja meg a tényleges "GenericDAO" típust. Osztály generic = field.getType (); Class classValue = field.getDeclaredAnnotation (DataAccess.class) .entity (); if (genericTypeIsValid (classValue, fieldGenericType)) {String beanName = classValue.getSimpleName () + generic.getSimpleName (); Object beanInstance = getBeanInstance (beanName, generic, classValue); field.set (bean, beanInstance);} else {dobja be az új IllegalArgumentException (ERROR_ENTITY_VALUE_NOT} (ERROR_ENTITY_VALUE_NOT} Class clazz, Type mező) {if (ParameterizedType mező példánya) {ParameterizedType parameterizedType = (ParameterizedType) mező; Type type = paraméterizedType.getActualTypeArguments () [0]; return type.equals (clazz);} else {logger.warn (WARN_VONALEN ); return true;}} public Object getBeanInstance (String beanName, Class genericClass, Class paramClass) {daoInstance = null; if (! configurableBeanFactory.containsBean (beanName)) {logger.info ("Új DataAccess bab létrehozása '{}'. ", babnév); Object toRegister = null; próbáld ki a {Constructor ctr = genericClass.getConstructor (Class.class); toRegister = ctr.newInstance (paramClass); } catch (e kivétel) {logger.error (ERROR_CREATE_INSTANCE, genericClass.getTypeName (), e); dobja új RuntimeException (e); } daoInstance = configurableBeanFactory.initializeBean (toRegister, babnév); configurableBeanFactory.autowireBeanProperties (daoInstance, AUTOWIRE_MODE, true); configurableBeanFactory.registerSingleton (babnév, daoInstance); logger.info ("A" {} "nevű bab sikeresen létrehozva.", beanName); } else {daoInstance = configurableBeanFactory.getBean (babnév); logger.info ("A (z)" {} "nevű bab már létezik, aktuális bab hivatkozásként használva.", beanName); } return daoInstance; }} 

Most - ez eléggé megvalósítás -, de ennek a legfontosabb része a csinálni vele() módszer:

genericDaoInstance = configurableBeanFactory.initializeBean (beanToRegister, beanName); configurableBeanFactory.autowireBeanProperties (genericDaoInstance, autowireMode, true); configurableBeanFactory.registerSingleton (babnév, genericDaoInstance); 

Ez azt mondaná Springnek, hogy inicializálja a babot a futás közben a @Adat hozzáférés annotáció.

A babnév gondoskodni fog arról, hogy kapunk egy egyedi példányt a babból, mert - ebben az esetben - egyetlen objektumot akarunk létrehozni GenericDao a @Adat hozzáférés annotáció.

Végül használjuk ezt az új babprocesszort a következő Spring konfigurációban.

3.5. CustomAnnotationConfiguration

@Configuration @ComponentScan ("com.baeldung.springcustomannotation") public class CustomAnnotationConfiguration {} 

Egy dolog, ami itt fontos, az a @ComponentScan a kommentárnak arra a csomagra kell mutatnia, ahol az egyedi bab-utómunka-feldolgozónk található, és meg kell győződnie arról, hogy a Spring futás közben beolvasta és automatikusan beküldte.

4. Az új DAO tesztelése

Kezdjük egy Spring engedélyezett teszttel és két egyszerű példa entitás osztállyal itt - Személy és Számla.

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (class = {CustomAnnotationConfiguration.class}) public class DataAccessAnnotationTest {@DataAccess (entitás = Személy.osztály) private GenericDao personGenericDao; @DataAccess (entitás = Account.class) privát GenericDao accountGenericDao; @DataAccess (entitás = Személy.osztály) privát GenericDao anotherPersonGenericDao; ...}

Injektálunk néhány példányt a GenericDao segítségével Adat hozzáférés annotáció. Annak teszteléséhez, hogy az új babot helyesen fecskendezték-e be, a következőket kell lefednünk:

  1. Ha az injekció sikeres
  2. Ha az azonos entitással rendelkező babpéldányok megegyeznek
  3. Ha a módszerek a GenericDao valóban az elvárásoknak megfelelően működik

Az 1. pontot tulajdonképpen maga Spring fedi le - mivel a keret meglehetősen korán kivételt vet, ha egy babot nem lehet bekötni.

A 2. pont teszteléséhez meg kell vizsgálnunk a GenericDao hogy mindkettő használja a Személy osztály:

@Test public void whenGenericDaoInjected_thenItIsSingleton () {assertThat (personGenericDao, not (sameInstance (accountGenericDao))); assertThat (personGenericDao, nem (equalTo (accountGenericDao))); assertThat (personGenericDao, sameInstance (egy másikPersonGenericDao)); }

Nem akarjuk personGenericDao hogy egyenlő legyen a accountGenericDao.

De azt akarjuk personGenericDao és anotherPersonGenericDao hogy pontosan ugyanaz a példa.

A 3. pont teszteléséhez itt egyszerűen tesztelünk néhány egyszerű kitartással kapcsolatos logikát:

@Test public void whenFindAll_thenMessagesIsCorrect () {personGenericDao.findAll (); assertThat (personGenericDao.getMessage (), is ("FindAll lekérdezést hozna létre a Személytől"); accountGenericDao.findAll (); assertThat (accountGenericDao.getMessage (), is ("FindAll lekérdezést hozna létre a fiókból"); } @Test public void whenPersist_thenMessagesIsCorrect () {personGenericDao.persist (new Person ()); assertThat (personGenericDao.getMessage (), is ("Folyamatos lekérdezést hozna létre a személytől"); accountGenericDao.persist (új fiók ()); assertThat (accountGenericDao.getMessage (), is ("Folyamatos lekérdezést hozna létre a fiókból")); } 

5. Következtetés

Ebben a cikkben az egyedi kommentárok nagyon jó végrehajtását hajtottuk végre tavasszal - a BeanPostProcessor. Az általános cél az volt, hogy megszabaduljunk a sok DAO-implementációtól, amelyek általában vannak a perzisztencia rétegünkben, és egy szép, egyszerű általános megvalósítást használunk anélkül, hogy bármit is vesztenénk a folyamat során.

Mindezen példák és kódrészletek megvalósítása ban található a GitHub projektem - ez egy Eclipse alapú projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.