Tervezési minták a tavaszi keretben

1. Bemutatkozás

A tervezési minták a szoftverfejlesztés elengedhetetlen részei. Ezek a megoldások nemcsak az ismétlődő problémákat oldják meg, hanem a közös minták felismerésével segítenek a fejlesztőknek megérteni a keretrendszert.

Ebben az oktatóanyagban a tavaszi keretben használt négy leggyakoribb tervezési mintát vizsgáljuk meg:

  1. Singleton minta
  2. Gyári módszer mintája
  3. Proxy minta
  4. Sablon minta

Megvizsgáljuk azt is, hogy a Spring hogyan használja ezeket a mintákat a fejlesztők terheinek csökkentésére és a felhasználók gyors unalmas feladatok elvégzésének elősegítésére.

2. Singleton minta

A szingulettmintázat olyan mechanizmus, amely biztosítja, hogy alkalmazásonként csak egy objektum létezik. Ez a minta hasznos lehet megosztott erőforrások kezelésekor vagy horizontális szolgáltatások, például naplózás biztosításakor.

2.1. Singleton Beans

Általában egy szingulett globálisan egyedülálló egy alkalmazás számára, de tavasszal ez a korlát enyhül. Helyette, A tavasz korlátozza egyetlen tárgy egy tárgyhoz tavaszi IoC konténerenként. A gyakorlatban ez azt jelenti, hogy a Spring alkalmazáskörnyezetenként csak egy babot hoz létre minden típushoz.

Spring megközelítése különbözik a szingulettek szigorú meghatározásától, mivel egy alkalmazásnak több Spring konténere is lehet. Ebből kifolyólag, Ugyanabban az osztályban több objektum is létezhet egyetlen alkalmazásban, ha több tárolónk van.

Alapértelmezés szerint a Spring minden babot szingliként hoz létre.

2.2. Autowired Singletons

Például létrehozhatunk két vezérlőt egyetlen alkalmazási környezetben, és mindegyikbe befecskendezhetünk egy azonos típusú babot.

Először létrehozunk egy BookRepository hogy kezeli a mi Könyv domain objektumok.

Ezután létrehozunk LibraryController, amely a BookRepository a könyvtárban lévő könyvek számának visszaadásához:

@RestController public class LibraryController {@Autowired private BookRepository repository; @GetMapping ("/ count") public Long findCount () {System.out.println (adattár); return repository.count (); }}

Végül létrehozunk egy BookController, amelyre összpontosít Könyv-specifikus műveletek, például egy könyv megtalálása az azonosítója alapján:

@RestController public class BookController {@Autowired private BookRepository repository; @GetMapping ("/ book / {id}") public Book findById (@PathVariable long id) {System.out.println (adattár); return repository.findById (id) .get (); }}

Ezután elindítjuk ezt az alkalmazást, és elvégezzük a GET-et /számol és / book / 1:

curl -X GET // localhost: 8080 / count curl -X GET // localhost: 8080 / book / 1

Az alkalmazás kimenetében azt látjuk, hogy mindkettő BookRepository az objektumok azonos objektumazonosítóval rendelkeznek:

[e-mail védett] [e-mail védett]

A BookRepository objektumazonosítók a LibraryController és BookController azonosak, bizonyítva, hogy Spring ugyanazt a babot injektálta mindkét kontrollerbe.

Külön példányokat hozhatunk létre a BookRepository babot a bab hatókörének megváltoztatásával szingli nak nek prototípus használni a @Hatókör (ConfigurableBeanFactory.SCOPE_PROTOTYPE)annotáció.

Ezzel utasítja Springet, hogy hozzon létre külön objektumokat az egyes BookRepository babot hoz létre. Ezért, ha megvizsgáljuk a BookRepository ismét mindegyik vezérlőnkben látjuk, hogy már nem ugyanazok.

3. Gyári módszer minta

A gyári metódus egy gyári osztályt tartalmaz, absztrakt módszerrel a kívánt objektum létrehozásához.

Gyakran különböző tárgyakat szeretnénk létrehozni egy adott kontextus alapján.

Például alkalmazásunkhoz szükség lehet jármű objektumra. Tengeri környezetben csónakokat akarunk létrehozni, repülőgép-környezetben azonban repülőgépeket:

Ennek megvalósításához minden kívánt objektumhoz létrehozhatunk egy gyári megvalósítást, és a betongyári módszerből visszaküldjük a kívánt objektumot.

3.1. Az alkalmazás kontextusa

Spring ezt a technikát alkalmazza a Dependency Injection (DI) keretrendszer gyökerében.

Alapvetően, Tavaszi csemegékbabtartály, mint babot termelő gyár.

Így Spring meghatározza a BeanFactory interfész babtartály absztrakciójaként:

nyilvános felület BeanFactory {getBean (Class requiredType); getBean (Class requiredType, Object ... érvel); getBean (karakterlánc neve); // ...]

Mindegyik getBean módszerek gyári módszernek számítanak, amely egy olyan babot ad vissza, amely megfelel a metódus kritériumainak, például a bab típusának és nevének.

A tavasz ekkor meghosszabbodik BeanFactory a ... val ApplicationContext interfész, amely további alkalmazáskonfigurációt vezet be. A Spring ezt a konfigurációt használja egy babtartály elindításához néhány külső konfiguráció alapján, például XML fájl vagy Java megjegyzések alapján.

Használni a ApplicationContext osztályos megvalósítások, mint AnnotationConfigApplicationContext, ezután babot hozhatunk létre a BeanFactory felület.

Először létrehozunk egy egyszerű alkalmazáskonfigurációt:

@Configuration @ComponentScan (basePackageClasses = ApplicationConfig.class) public class ApplicationConfig {}

Ezután létrehozunk egy egyszerű osztályt, Foo, amely nem fogad el konstruktor érveket:

@Component public class Foo {}

Ezután hozz létre egy másik osztályt, Rúd, amely egyetlen konstruktor argumentumot fogad el:

@Component @Scope (ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class Bar {private String name; nyilvános sáv (karakterlánc neve) {this.name = név; } // Getter ...}

Végül a babonkat a AnnotationConfigApplicationContext végrehajtása ApplicationContext:

@Test public void whenGetSimpleBean_thenReturnConstrucedBean () {ApplicationContext context = new AnnotationConfigApplicationContext (ApplicationConfig.class); Foo foo = context.getBean (Foo.osztály); assertNotNull (foo); } @Test public void whenGetPrototypeBean_thenReturnConstrucedBean () {String várhatóNév = "Néhány név"; ApplicationContext context = új AnnotationConfigApplicationContext (ApplicationConfig.class); Bar bar = context.getBean (Bar.class, várhatóNév); assertNotNull (bár); assertThat (bar.getName (), van (várhatóNév)); }

Használni a getBean gyári módszerrel konfigurált babot hozhatunk létre csak az osztálytípus és - esetén Rúd - konstruktor paraméterei.

3.2. Külső konfiguráció

Ez a minta sokoldalú, mert a külső konfiguráció alapján teljesen megváltoztathatjuk az alkalmazás viselkedését.

Ha meg akarjuk változtatni az alkalmazásban az automatikusan bekötött objektumok megvalósítását, akkor a ApplicationContext az általunk alkalmazott megvalósítás.

Például megváltoztathatjuk a AnnotationConfigApplicationContext egy XML-alapú konfigurációs osztályba, mint pl ClassPathXmlApplicationContext:

@Test public void givenXmlConfiguration_whenGetPrototypeBean_thenReturnConstrucedBean () {String várhatóNév = "Néhány név"; ApplicationContext context = new ClassPathXmlApplicationContext ("context.xml"); // Ugyanaz a teszt, mint korábban ...}

4. Proxy minta

A meghatalmazottak hasznos eszköz a digitális világunkban, és nagyon gyakran használjuk őket a szoftvereken kívül (például a hálózati proxykon). Kódban, a proxy minta egy olyan technika, amely lehetővé teszi az egyik objektumnak - a proxy - a hozzáférést egy másik objektumhoz - az alanyhoz vagy a szolgáltatáshoz.

4.1. Tranzakciók

Proxy létrehozásához létrehozunk egy objektumot, amely ugyanazt az interfészt valósítja meg, mint az alanyunk, és tartalmaz egy hivatkozást az alanyra.

Ezután a tárgy helyett használhatjuk a proxyt.

Tavasszal a babot meghatalmazva ellenőrzik az alapul szolgáló babhoz való hozzáférést. Ezt a megközelítést látjuk tranzakciók használata során:

@Service public class BookManager {@Autowired private BookRepository repository; @Transactional public Book create (karakterlánc-készítő) {System.out.println (repository.getClass (). GetName ()); return repository.create (szerző); }}

Miénkben BookManager osztályban jegyzeteljük a teremt módszer a @ Tranzakció annotáció. Ez az annotáció arra utasítja Springet, hogy atomikusan hajtsa végre a mi feladatunkat teremt módszer. Meghatalmazó nélkül Spring nem tudná ellenőrizni a mi hozzáférésünket BookRepository babot, és biztosítja annak tranzakciós következetességét.

4.2. CGLib Proxies

Helyette, A tavasz létrehoz egy proxyt, amely bebugyolálja a mieinket BookRepository bab és műszereket ad a babunkra, hogy kivégezzük teremt módszer atomi úton.

Amikor hívjuk a miénk BookManager # létrehozás módszerrel láthatjuk a kimenetet:

com.baeldung.patterns.proxy.BookRepository $$ EnhancerBySpringCGLIB $$ 3dc2b55c

Jellemzően elvárnánk, hogy színvonalat találjunk BookRepository objektum azonosítója; ehelyett egy EnhancerBySpringCGLIB objektum azonosítója.

A színfalak mögött, A tavasz bebugyolálta BookRepository tárgy belül EnhancerBySpringCGLIB tárgy. A tavasz így ellenőrzi a hozzáférést a mi BookRepository objektum (ügyleti konzisztencia biztosítása).

Általában a Spring kétféle proxyt használ:

  1. CGLib proxyk - osztályok proxykozásakor használják
  2. JDK Dynamic Proxies - Felületek proxyként történő használatakor használatos

Míg tranzakciókat használtunk az alapul szolgáló proxyk felfedésére, A tavasz minden olyan forgatókönyv esetén meghatalmazottat használ, amelyben ellenőriznie kell a babhoz való hozzáférést.

5. Sablon módszer mintája

Számos keretrendszerben a kód jelentős része a kazánlap kódja.

Például egy lekérdezés adatbázisban történő végrehajtásakor ugyanazt a lépéssorozatot kell végrehajtani:

  1. Hozza létre a kapcsolatot
  2. Végezze el a lekérdezést
  3. Végezze el a tisztítást
  4. Zárja le a kapcsolatot

Ezek a lépések ideális forgatókönyvek a sablon módszer mintájához.

5.1. Sablonok és visszahívások

A sablon metódus egy olyan technika, amely meghatározza az egyes műveletekhez szükséges lépéseket, végrehajtja a kazán lépéseit, és a testreszabható lépéseket elvontként hagyja. Ezután az alosztályok megvalósíthatják ezt az absztrakt osztályt, és konkrét megvalósítást nyújthatnak a hiányzó lépésekhez.

Hozhatunk létre sablont az adatbázis lekérdezésünk esetében:

public abstract DatabaseQuery {public void execute () {Connection connection = createConnection (); executeQuery (kapcsolat); closeConnection (kapcsolat); } védett Connection createConnection () {// Csatlakozás adatbázishoz ...} védett void closeConnection (Csatlakozási kapcsolat) {// Kapcsolat bezárása ...} védett absztrakt void executeQuery (Csatlakozási kapcsolat); }

Alternatív megoldásként a visszahívási módszer megadásával biztosíthatjuk a hiányzó lépést.

A visszahívási módszer olyan módszer, amely lehetővé teszi az alany számára, hogy jelezze az ügyfélnek, hogy valamilyen kívánt művelet végrehajtásra került.

Bizonyos esetekben az alany ezt a visszahívást használhatja olyan műveletek végrehajtására, mint például az eredmények feltérképezése.

Például ahelyett, hogy executeQuery módszerrel tudjuk szállítani a végrehajtani metódus egy lekérdezési karakterlánc és egy visszahívási módszer az eredmények kezeléséhez.

Először létrehozzuk a visszahívási módszert, amely a Eredmények objektumot, és egy típusú objektumra térképezi fel T:

nyilvános felület ResultsMapper {nyilvános T térkép (Eredmények eredményei); }

Aztán változtatunk DatabaseQuery osztály használja ezt a visszahívást:

public abstract DatabaseQuery {public T végrehajtani (String lekérdezés, ResultsMapper leképező) {Connection connection = createConnection (); Eredményeredmények = executeQuery (kapcsolat, lekérdezés); closeConnection (kapcsolat); return mapper.map (eredmények); ] védett eredmények executeQuery (csatlakozási kapcsolat, karakterlánc lekérdezés) {// Lekérdezés végrehajtása ...}}

Ez a visszahívási mechanizmus pontosan azt a megközelítést alkalmazza, amelyet Spring a JdbcTemplate osztály.

5.2. JdbcTemplate

A JdbcTemplate osztály biztosítja a lekérdezés metódus, amely elfogad egy lekérdezést Húr és ResultSetExtractor tárgy:

public class JdbcTemplate {public T query (végleges String sql, végleges ResultSetExtractor rse) dobja a DataAccessException {// lekérdezés végrehajtása ...} // Egyéb módszerek ...}

A ResultSetExtractor átalakítja a ResultSet objektum - amely a lekérdezés eredményét képviseli - egy típusú tartomány objektummá T:

@FunctionalInterface nyilvános felület ResultSetExtractor {T extractData (ResultSet rs) dobja az SQLException, DataAccessException; }

A Spring tovább csökkenti a kazánlap kódját azáltal, hogy specifikusabb visszahívási interfészeket hoz létre.

Például a RowMapper interfész segítségével egyetlen sor SQL adat konvertálható egy típusú tartomány objektummá T.

@FunctionalInterface nyilvános felület RowMapper {T mapRow (ResultSet rs, int rowNum) dob SQLException; }

A RowMapper interfész a várható ResultSetExtractor, Tavasz létrehozza a RowMapperResultSetExtractor osztály:

public class JdbcTemplate {public list query (String sql, RowMapper rowMapper) throws DataAccessException {return result (query (sql, new RowMapperResultSetExtractor (rowMapper))); } // Egyéb módszerek ...}

Ahelyett, hogy logikát adna egy egész átalakításához ResultSet objektumot, beleértve a sorok feletti iterációt, logikát tudunk adni arról, hogyan lehet egyetlen sort konvertálni:

public class BookRowMapper megvalósítja a RowMapper {@Orride public Book mapRow (ResultSet rs, int rowNum) dob SQLException {Book book = new Book (); book.setId (rs.getLong ("id")); book.setTitle (rs.getString ("cím")); book.setAuthor (rs.getString ("szerző")); visszatérő könyv; }}

Ezzel a konverterrel ezután lekérdezhetünk egy adatbázist a JdbcTemplate és térképezze fel az egyes kapott sorokat:

JdbcTemplate template = // sablon létrehozása ... template.query ("SELECT * FROM könyvek", új BookRowMapper ());

A JDBC adatbázis-kezelés mellett a Spring sablonokat is használ:

  • Java üzenetszolgáltatás (JMS)
  • Java Persistence API (JPA)
  • Hibernálás (már elavult)
  • Tranzakciók

6. Következtetés

Ebben az oktatóanyagban a tavaszi keretben alkalmazott négy leggyakoribb tervezési mintát vizsgáltuk.

Megvizsgáltuk azt is, hogy a Spring hogyan használja ezeket a mintákat gazdag funkciók biztosítására, miközben csökkenti a fejlesztők terheit.

A cikk kódja a GitHub oldalon található.