Obsah
K dosažení tohoto ideálního stavu vede budto čistě formální cesta:
Dále zmiňované nástroje však toto nedokážou; omezují se na běhovou kontrolu platnosti předpsaných podmínek
jass je preprocesor javového zdrojového textu. Umožňuje ve zdrojovém textu programu vyznačit podmínky, jejichž splnění je za běhu kontrolováno.
jass
stažení a instalace balíku z http://csd.informatik.uni-oldenburg.de/~jass/
vytvoření zdrojového textu s příponou
.jass
, javovou syntaxí s použitím speciálních
komentářových značek
takový zdrojový text je přeložitelný i normálním překladačem javac, ale v takovém případě ztrácíme možnosti jass
proto nejprve .jass
souboru převedeme
preprocesorem jass na javový (.java
)
soubor
ten již přeložíme javac a spustíme java, tedy jako každý jiný zdrojový soubor v Javě
z .jass
zdrojů je možné vytvořit také
dokumentaci API obsahující jass značky, tj. informace, co kde musí
platit za podmínky atd. - vynikající možnost!
úvodní materiálek k použití junit (v němčině, jako PDF)
Uvádíme pragmaticky jen to, co je potřeba zde (pro potřeby IoC), nechápat jako komplexní terminologii.
objekt poskytující navenek ucelenou funkcionalitu (část aplikační nebo pomocné logiky)
komponenta je obvykle chápána jako "velký objekt" nebo graf více objektů s vnějším rozhraním ("fasádou")
komponenta je sice do jisté míry samostatná, ale většinou nežije nezávisle; za běhu potřebuje návaznosti na další komponenty nebo hostující rámec (kontejner)
objekt, v němž jsou za běhu aplikace uloženy a spravovány komponenty (objekty)
kontejner dokáže většinou komponenty i vytvářet a poskytovat odkazy na ně (vyhledávat je)
V komponentních systémech bývá tradičním problémem zajistit správnou inicializaci a provoz komponent závislých na ostatních.
Co je třeba udělat při nasazení jedné nové komponenty
Postup vypadá přímočaře, ale je bohužel rekurentní... v bodě 1 (připravit komponenty...) se opakuje rekurentně celý postup
V Inversion of Control obracíme tento (pro komponentního programátora) nepraktický, obtížný postup.
O řešení závislostí se postará rámec (kontejner), komponenta pouze deklaruje na čem závisí.
Historicky se postupně vyvinuly tři přístupy k "injektáži" potřebných závislostí; tedy k IoC:
Blíže viz popis k IoC v systému (rámci) vraptor a následující slidy.
Komponenta MUSÍ IMPLEMENTOVAT určité, rámcem/kontejnerem dané rozhraní (příklad z článku Intro. to AOP):
import org.apache.avalon.framework.*;
public class JDBCDataManger implements Serviceable {
DataSource dataSource;
public void service (ServiceManager sm)
throws ServiceException {
dataSource = (DataSource)sm.lookup("dataSource");
}
public void getData() {
//use dataSource for something
}
}
Nevýhoda: musí implementovat dané rozhraní, nelze vyvíjet zcela nezávisle.
Komponenta je jako objekt JavaBean, má setXXX metody:
public class JDBCDataManger {
private DataSource dataSource;
public void setDataManager(DataSource dataSource {
this.dataSource = dataSource;
}
public void getData() {
//use dataSource for something
}
}
Rámec (kontejner), např. Spring musí vědět, jak komponentu vytvořit a na čem závisí:
<bean id="myDataSource"
class="org.apache.commons.dbcp.BasicDataSource" >
<property name="driverClassName">
<value>com.mydb.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mydb://server:port/mydb</value>
</property>
<property name="username">
<value>root</value>
</property>
</bean>
<bean id="dataManager"
class="example.JDBCDataManger">
<property name="dataSource">
<ref bean="myDataSource"/>
</property>
</bean>
Oproti Interface Injection: netřeba implementovat rozhraní
Je ale nezřetelné, které setXXX metody jsou pro účely nastavení závislostí přes Setter Injection a které ne.
public class JDBCDataManger {
private DataSource dataSource;
public JDBCDataManger(DataSource dataSource) {
this.dataSource = dataSource;
}
public void getData() {
//use dataSource for something
}
}
Existují jednoduché (lightweight) kontejnery pro nasazení a provoz komponent s využitím IoC.
Tyto kontejnery mnohdy neumí nic navíc, jde jen o základní správu komponent.
Příkladem je PicoContainer a Spring, který je však komplexnější (a složitější).
Programový kód rozsáhlejších soudobých systémů je složitý, nepřehledný, nesnadno udržovatelný.
U systémů jsou často implementovány mimofunkční požadavky: protokolování, zabezpečení, optimalizace.
Pokrytí těchto požadavků jde napříč s požadavky funkčními - současné splnění vede nezřídka ke kombinatorické explozi a (téměř) exponenciálnímu nárůstu velikosti kódu.
Kód je nečitelný a ještě obtížněji udržovatelný.
I rozšiřování nelze většinou provést lokálně, nezřídka je jím zasaženo více částí kódu.
Příklad převzatý z weblogu Jablok Pavla Kolesnikova (typický kód aplikační logiky):
public class KusAplikacniLogiky extends ObecnejsiKus {
// data tridy;
// jina pomocna data;
// pretizeni rodicovskych metod
public void provedNecoPodstatneho () {
// autentizace
// autorizace
// dalsi nezajimavy kod
// logovani zacatku operace
// vlastni aplikacni logika — konecne!
// logovani ukonceni operace
// treba jeste neco
}
}
Překlad článku Graham O'Regana Introduction to Aspect-Oriented Programming na onjava.com nastiňuje hlavní principy:
AOP umožňuje přidat do statického OO modelu programu (třídy) dynamické aspekty - např. ovlivňovat (vstupovat do) volání metod.
Např. servlet očekává vstup z webového formuláře, naváže data z formuláře do vytvořeného datového objektu, ten zpracuje aplikační logikou a výsledek prezentuje.
Kromě toho ale musí řešit:
ošetření výjimek
zabezpečení přístupu
protokolování
Postupy AOP řadíme mezi deklarativní programování.
Deklarativní programování pomocí anotací bylo zmiňováno u Java Persistence API.
záměr jdoucí napříč třídami (přes více tříd)
v podstatě modularizace crosscutting concern
význačné místo v provádění programu - např. vstup nebo opuštění metody
- místo, kde se uplatní aspekt
podmínka, za níž se v místě join point uplatní pokyn (advice)
vložení atributu nebo metody
pokyn, co se má v daném bodě (pointcut) provést
Inversion of Control (IoC)
návrhový vzor, o instanciaci a správu objektů aplikace se stará třetí strana - Spring
Dependency Injection (DI)
návrhový vzor, zajišťující provázání závislých objektů
Plain Old Java Object (POJO)
označení objektů, které nejsou žádným způsobem závislé na aplikačním rámci, který je spravuje, takové objekty jsou snadno znovupoužitelné v různých prostředích - ve webové aplikaci, v EJB aplikaci, v testovacím prostředí, atd.
Spring poskytuje specifické služby objektům aplikační (business) vrstvy
podobný podpůrný rámec dosud chyběl (mimo EJB)
Spring se zaměřuje na správu jednotlivých objektů, nikoliv celých komponentpod
pora zajištěna primárně prostřednictvím IoC a AOP
Spring umožňuje správu POJO objektů (EJB nikoliv)
spravované objekty musí mít formát JavaBeans - bezparametrický konstruktor a set/get metody
Kontejner rámce Spring (nazývaný také aplikační kontext) při svém startu načte definiční soubor. Na základě definic v něm uvedených vytvoří pomocí reflexe specifikované objekty, vzájemně je prováže a tuto síť objektů spravuje po dobu běhu aplikace.
Definiční soubor:
v drtivé většině případů je používán XML soubor
lze použít i soubor ve formátu properties
<beans> <bean id="nejakaFirma" class="cz.neco.Zamestnavatel" /> <bean id="franta" class="cz.neco.Zamestnanec" > <property name="jmeno"><value>František Novák</value></property> <property name="zamestnavatel" ><ref bean="nejakaFirma" /></property> </bean> </beans>
V tomto případě by kontejner prostřednictvím reflexe provedl kód ekvivalentní tomuto:
Zamestnavatel nejakaFirma = new Zamestnavatel();
Zamestnanec franta = new Zamestnanec();
Franta.setJmeno = "František Novák";
Franta.setZamestnavatel(nejakaFirma);
Pojmenujeme-li tento definiční XML soubor "kontext.xml" a umístíme-li jej do classpath, pak kontejner nastartujeme například takto:
ApplicationContext context = new ClassPathXmlApplicationContext("/kontext.xml");
Vytvořeného zaměstnance s id "franta" získáme z kontejneru voláním:
Zamestnanec z = (Zamestnanec)context.getBean("franta");
Pomocí dalších deklarací v tomtéž XML souboru lze definovat, jakým způsobem budou dříve vyjmenované služby poskytnuty našim objektům. Naše třídy se tedy nemusí například transakčním či bezpečnostním managementem zabývat, vše zajistí Spring.
Komponenta koncipovaná jako MBean je často vytvářena takto:
Co odlišuje skriptování od "ostatních" pg. jazyků?
Rychlý vývoj, přímočarý životní cyklus SW: napiš - spusť (- potom odlaď)
Obvyklé dynamicky (až za běhu) typovaný jazyk, nevyžaduje deklarace proměnných, definice tříd...
Jazyk je často kombinovatelný s běžnými pg. jazyky - lze volat jejich metody, používat knihovny...
Prostá, obvykle intuitivní, syntaxe
Mnohdy jde de-facto o syntaktický klon "plného" jazyka - mj. aby se snáze učilo
Obvykle malé nároky na udržovatelnost, dokumentovatelnost, rozšiřitelnost vzniklých SW výtvorů
Jednoduché věci jdou napsat jednoduše, složité složitě, nepěkně nebo pořádně vůbec...
Proč je potřeba skriptovat silná právě dnes, když je tolik dokonalých programovacích jazyků s rychlými překladači?
Bean Scripting Framework (BSF) je projektem jakarta.apache.org, původně však vytvořený v IBM T.J.Watson Laboratories (jako produkt "alphaWorks").
BSF (software i další info) lze získat na http://jakarta.apache.org/bsf.
Vynikající články o BSF jsou k dispozici přímo na http://jakarta.apache.org/bsf/resources.html.
http://www.javaworld.com/javaworld/jw-03-2000/jw-03-beans.html
Definice mapy (asociativního pole) a přístup k prvku:
map = ["name":"Gromit", "likes":"cheese", "id":1234]
assert map['name'] == "Gromit"
Řízení toku pomocí switch s velmi bohatými možnostmi:
x = 1.23
result = ""
switch (x) {
case "foo":
result = "found foo"
// lets fall through
case "bar":
result += "bar"
case [4, 5, 6, 'inList']:
result = "list"
break
case 12..30:
result = "range"
break
case Integer:
result = "integer"
break
case Number:
result = "number"
break default:
result = "default"
}
assert result == "number"
Existuje několik "standardních" protokolovacích API:
od Java 1.4: balík java.util.logging
již dříve nezávislé open-source řešení log4j
Obě řešení jsou srovnatelná, log4j je o něco elegantnější a propracovanější. Nejlépe (pokud to stačí) je použít zastřešujícího API:
Existuje několik "standardních" protokolovacích API:
od Java 1.4: balík java.util.logging
již dříve nezávislé open-source řešení log4j
Obě řešení jsou srovnatelná, log4j je o něco elegantnější a propracovanější. Nejlépe (pokud to stačí) je použít zastřešujícího API: