Spring scope

Rozsahy platnosti (scope) Java bean jsou už ve Springu dlouho, od verze 2.0. Až donedávna mi ale nedošlo o jak silný nástroj se jedná. Pro ty, kteří nejsou s konceptem rozsahu platnosti obeznámeni, uvedu krátké shrnutí, podrobnější detaily se dočtete zde.

Už od první verze Springu, si člověk u každého beanu mohl zvolit, jestli chce aby se choval jako sigleton (jedináček) nebo aby bean factory pokaždé vracela novou instanci (prototype). Spring 2 zavedl další rozsahy, mezi jinými i scope session a request. Co to znamená? U webové aplikace, můžeme Springu říci, aby vracel jednu a tu samou instanci v rámci HTTP session nebo requestu. Nejlépe to půjde vysvětlit na příkladě. Mějme následující kontroler.



01 public class AddToCartController implements Controller {
02   private Cart cart;
03   public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resthrows Exception {
04     String itemName = ServletRequestUtils.getRequiredStringParameter(req, "itemName");
05     cart.addItem(itemName);
06     return new ModelAndView("redirect:viewCart.spg");
07   }
08   public Cart getCart() {
09     return cart;
10   }
11   public void setCart(Cart cart) {
12     this.cart = cart;
13   }
14 }

Vidíme, že tu jednoduše přidáváme položku do nákupního košíku. Ale počkat, co to je za nesmysl, vždyť ten kód vypadá, jako by naše aplikace mohla mít jenom jeden košík, společný pro všechny zákazníky! A to je právě to kouzlo rozsahů platnosti ve Springu, aplikaci mohu psát tak, jako by měla jenom jednoho uživatele. Aby to fungovalo, musím v konfiguračním souboru Springu říci, že má pro každou session vytvořit novou instanci.

<bean id="cart" 
	class="net.krecan.javacrumbs.stshop.SimpleCart" 
	scope="session">
	<aop:scoped-proxy proxy-target-class="false"/>
</bean>
<bean name="/addToCart.spg" 
	class="net.krecan.javacrumbs.stshop.AddToCartController">
	<property name="cart" ref="cart"/>
</bean>

Všimněte si prosím, kousku konfigurace <aop:scoped-proxy proxy-target-class="false"/>. Ten je tam z toho důvodu, že kontroler do kterého injektujeme je normální sigleton. To znamená, že k jeho inicializaci a nastavení všech závislostí dochází jenom jednou. Z toho plyne, že by se nám s kontrolerem napevno spojil právě jeden nákupní košík. Uvedený tag zajistí, že se do kontroleru vloží proxy objekt, který deleguje všechnu svoji činnost na instanci košíku vytaženou z HTTP session.

Na první pohled na tom není nic převratného, už jsem o tom dokonce i jednou psal. Tenkrát mi ale nedošly všechny důsledky, které podobná funkcionalita přináší. Mohu bez problémů psát webové aplikace tak, jako by s nimi pracoval jenom jeden uživatel. Nemusím si všude předávat pomocí parametrů id uživatele. Pokud to uznám za vhodné, mohu nákupní košík vložit přímo do business vrstvy, která s ním pracuje. Ano, je to hodně nezvyklé a může to mást programátory, kteří jsou zvyklí na klasické bezstavové J2EE programování. Když jsem to poprvé použil, tak se mi to hodně nelíbilo. Z kontroleru jsem chtěl volat jakýsi CartService, který by všechno zařídil. Pak mi ale došlo, že to, na co jsem zvyklý, je v podstatě procedurální programování. CartService obsahuje procedury, kterým předávám takovou chytřejší strukturu Cart. V objektovém programování se nákupní košík o sebe musí umět postarat sám. V uvedeném příkladě to tak je. Dokonce když chci, tak Cart může obsahovat referenci na DAO, která uloží změny do databáze. Koukněte se prosím na příklad ještě jednou, obdobně by vypadal listener ve standalone aplikaci. Co myslíte, jsem úplně mimo, nebo je to ten správný krok k návratu k objektovému programování?

Zdrojové kódy jsou ke stažení pomocí SVN na adrese https://java-crumbs.svn.sourceforge.net/svnroot/java-crumbs/spring-terracotta-shop/

2 thoughts on “Spring scope

  1. Vlasta

    Tento přístup se mi zdá být super. Podobný princip používám při spojení Spring a DWR. Tam lze využít toho že DWR automaticky injektne aktuální request do servisní metody, která ho v parametrech obsahuje.

  2. Petr Ferschmann

    Zdravím,

    jojo, musím potvrdit, že toto je dobrý přístup. Je hodně používaný i např. v Seamu nebo PicoContaineru (i když tam ty okraje platnosti rozsahu musí člověk řídit ručně).

Comments are closed.