Minule jsme si s pomocí Springu vytvořili maximálně jednoduchou webovou aplikaci a dnes bychom měli začít s jejím rozborem. Řekneme si, co je to aplikační kontext a jak je vytvořen na základě konfiguračního souboru ve formátu XML. Zmíníme se také o IoC a jeho alternativách.
Vzhledem k tomu, že budeme vycházet z minule uvedeného příkladu, bude asi výhodné otevřít si předchozí díl do jiného okna a příklad průběžně sledovat.
DispatcherServlet
Začneme velmi lehce u třídy DispatcherServlet. Objekt této třídy zpracovává všechny požadavky, které na naši aplikaci přicházejí. Je samozřejmě možné mít ve web.xml definovaných více instancí této třídy (mapovaných na různé cesty) a rozdělit tak logicky celou aplikaci na relativně nezávislé Springem spravované části. Například aplikace spravující webové stránky, na kterých se právě nacházíte, má dva takovéto vstupní body. První z nich je nastaven na cestu “/“ a spravuje stránky naši firemní prezentace, druhý pak na cestu “/blog“, kde operuje náš redakční systém. Později nám to umožní snadný upgrade blogu bez ovlivnění firemních stránek.
Instance třídy DispatcherServlet tedy při startu webové aplikace načte z defaultního umístění (/WEB-INF/(servlet-name)-servlet.xml a v našem případě tedy /WEB-INF/example-servlet.xml) soubor s konfiguračními informacemi a na jeho základě vytvoří a prováže definované objekty.
Aplikační kontext
Abychom byli alespoň trochu přesnější, Spring na základě našeho XML souboru vytvoří tzv. aplikační kontext, tedy instanci třídy XmlWebApplicationContext, jež implementuje rozhraní ApplicationContext. Toto rozhraní je středobodem celého Springu. Implementující třídy vytvoří a udržují síť objektů, ze kterých se aplikace skládá a které jsou takto propojeny jen velmi volně. Změna vzájemné závislosti objektů je například v případě XML aplikačních kontextů (a tyto výrazně převažují) jen otázkou konfigurace v době nasazení aplikace, tzn. že do zdrojových kódu není třeba zasahovat. Aplikační kontext je právě tou částí Springu, která představuje aplikaci principu Inversion of Control (IoC).
Konfigurační XML soubor
Struktura XML souboru je velmi jednoduchá. V našem příkladě vypadal obsah tohoto souboru takto:
< ?xml version="1.0" encoding="UTF-8"?> < !DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "https://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/">homeController</prop> </props> </property> </bean> <bean id="typicalViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix"><value>/WEB-INF/jsp/</value></property> <property name="suffix"><value>.jsp</value></property> </bean> <bean id="homeController" class="spring.example.HomeController"></bean> </beans>
Každý element bean přestavuje jednu instanci nějaké – atributem class definované – třídy. Objekty spravované aplikačním kontextem Springu musí dodržovat formát JavaBeans, tedy zjednodušeně řečeno obsahovat bezparametrický konstruktor a „get“ a „set“ metody, které definují jaké vlastnosti (properties) daný JavaBean má. Odtud také názvy elementů v XML konfiguracích Springu. Vnořený element property pak tedy zastupuje vlastnost daného JavaBeanu. Při vytváření aplikačního kontextu se ve třídě DispatcherServlet odehraje asi toto:
ApplicationContext context = new XmlWebApplicationContext(“example-servlet.xml”);
V uvedeném konstruktoru je XML soubor rozpársován a na jeho základě je vykonán přibližně tento kód.
HandlerMapping bean1 = new SimpleUrlHandlerMapping(); ViewResolver bean2 = new InternalResourceViewResolver(); Controller bean3 = new HomeController(); bean1.setMapping(new Properties().setProperty("/","homeController"); bean2.setPrefix("/WEB-INF/jsp/"); bean2.setSuffix(".jsp");
pozn: Všimněte si důsledného programování do rozhraní, nikoliv do implementací. To jsou samozřejmě základy OO programování a Spring vás je může naučit ?.
Uvedený úryvek toho, jakým způsobem jsou údaje z XML souboru mapovány na kód, který je na jeho základě proveden, je pouze demonstrační. Nejde o výtah z kódu Springu.
Náš příklad je trochu nešťastný v tom, že nedemonstruje hlavní výhodu, která nám z používání IoC plyne, tedy nastavení závislostí mezi našimi objekty. Zkusíme si tedy představit trochu složitější a také reálnější situaci, kdy náš HomeController využívá nějaký business objekt pro vykonání aplikační logiky. Takový objekt, řekněme instance rozhraní Service, je tedy jeho atributem:
public class HomeController implements Controller { private Service service; public void setService { … } /* v těle Controlleru, nejspíše tedy v metodě __handleRequest__, je objekt __service__ zavolán a vykoná aplikační logiku */ }
Servisní objekt by pak vypadal takto:
public class SomeService implements Service { … }
A upravený konfigurační soubor:
<bean id="homeController" class="spring.example.HomeController" > <property name=”service”> <ref bean=”someService”></ref> </property> </bean> <bean id=”someService” class=”spring.example.SomeService”></bean>
V tomto případě budou tedy nejdříve vytvořeny instance obou tříd a následně objekt s id someService bude prostřednictvím metody setService předán objektu s id homeController. Pokud bychom chtěli v budoucnu změnit typ servisního objektu, který bude pro náš kontroler vykonávat business logiku, stačí změnit deklaraci v konfiguráku.
To, co jsme si dnes řekli k obsahu konfiguračního souboru je naprostý základ. Existuje samozřejmě množství dalších možných nastavení – a my se k nim dostaneme – avšak námi rozebrané principy by měli stačit na množství jednodušších projektů.
Alternativy k IoC
Takže to je IoC v praxi. V předIoC obdobích se provázání objektů dosahovalo buď přímo klasickým
this.service = new SomeService();
případně různými “lookup” mechanismy (např. JNDI) či aplikací návrhového vzoru Service Locator. Přestože v tomto pořadí šlo vždy o krok kupředu, všechna tato řešení jsou horší než IoC, a to zejména z hlediska příliš úzkého vzájemného svázání objektů a zhoršené čitelnosti a udržovatelnosti kódu (“lookup” metody všude, kam se podíváš).
Takže dnešní díl končíme ve stavu, kdy aplikace je nastartována a v paměti je vytvořen objekt rozhraní ApplicationContext, který provázal a drží odkazy na v XML souboru definované objekty.
Příště se mrknem na Spring MVC workflow.
Napsat komentář