1. Spring framework
Motto: Musíte rozbít vejce když chcete udělat omeletu
Spring framework training materials by Roman Pichlík is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Sunday 13 May 2012 1
2. IoC container
Základy
Sunday 13 May 2012 2
Proč vzniknul Spring
Spring koncepce a organizace
Co spring nabízí a k čemu jej můžete použít
3. Agenda
• IoC obecně
• Chrakteristika
• XML
• Anotace
• Pokročilé techniky
• Čeho se vyvarovat
Sunday 13 May 2012 3
5. • Příklad Rezervace knih
• Mějme rozhraní ReservationService, které slouží k
rezervaci knih
• Mějme rozhraní BookStoreDao, které slouží k načítání
informací o knihách
• Implementa ReservationService používá BookStoreDao
pro čtení a ukládání knih z disku
• Existuje implementace FileSystemBookStoreDao
• Naimplementujte tyto třídy, aby prošel
ReservationServiceTest
Sunday 13 May 2012 5
- predpripraveny projekt sandbox
- implementace BookService, knihy mohou byt v souboru viz trida Helper
6. Typický kód
public class ReservationServiceImpl implements ReservationService{
private BookStoreDao bookStoreDao;
public ReservationServiceImpl() {
init();
}
private void init() {
File dataDirectory = new File("/tmp/data");
bookStoreDao = new FileSystemBookStoreDao(dataDirectory);
}
public boolean reserveBook(Long bookId) {
Book book = bookStoreDao.getBook(bookId);
//kod pro rezervaci vynechan
}
}
Sunday 13 May 2012 6
7. Poznej svého nepřítele
public class ReservationServiceImpl implements ReservationService{
private BookStoreDao bookStoreDao;
public ReservationServiceImpl() {
}
init();
1 cesta ve zdrojovém kódu
private void init() {
File dataDirectory = new File("/tmp/data");
bookStoreDao = new FileSystemBookStoreDao(dataDirectory);
}
public boolean reserveBook(Long bookId) {
Book book = bookStoreDao.getBook(bookId);
2 konkrétní implementace
//kod pro rezervaci vynechan
}
}
Sunday 13 May 2012 7
- konkretni implementace BookStore (WS, Database)
- nutno vedet jakym zpusobem nainicializovat
- cesta na tvrdo
8. Generalizace problému
• Kde najít
• Jak získat
• Jak zkonfigurovat
• Jak spojit
dohromady
Sunday 13 May 2012 8
- komponenty
10. Sunday 13 May 2012 10
Martin Fowler - Continuous Integration, Refactoring, Inversion of Control
11. Obrácená
kontrola
(řízení)
„…vychází z principu přenesení
odpovědnosti za nalezení, konfiguraci
a spojení komponent dohromady na
někoho třetího“
Sunday 13 May 2012 11
12. Dependency injection
Sunday 13 May 2012 12
- komponenty nevi (nemusi pokud nechteji) o tom, ze je nekdo managuje
- HOLLYWOOD princip
14. Service Locator vs. DI
• Preferujte DI
• Žádné těsné vazby
• Transparentní
• No singleton hell
• Service locator
• body napojení
• Servlet/Controller aplikace
Sunday 13 May 2012 14
16. POJO
public class ReservationServiceImpl implements ReservationService{
private BookStoreDao bookStoreDao;
public ReservationServiceImpl() {
}
public boolean reserveBook(Long bookId) {
Book book = bookStoreDao.getBook(bookId);
//kod pro rezervaci vynechan
}
}
Sunday 13 May 2012 16
17. Metadata
@Component @Component
public class ReservationServiceImpl implements public class FileSystemBookStoreDao implements BookStoreDao{
ReservationService{
@Autowired private File rootPath;
private BookStoreDao bookStoreDao;
@Autowired
public ReservationServiceImpl() { public FileSystemBookStoreDao(File rootPath) {
} //kod vynechan
}
public boolean reserveBook(Long bookId) {
Book book = bookStoreDao.getBook(bookId); }
//kod pro rezervaci vynechan
return false;
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="cz.sweb.pichlik.impl"/>
<bean class="java.io.File">
<constructor-arg value="/mnt/data" />
</bean>
</beans>
Sunday 13 May 2012 17
21. Benefity
• Indirekce == volné vazby
• Znovupoužitelnost
• Lepší testovatelnost
• Extensibilita
Sunday 13 May 2012 21
- komponenty na sobe nezavisi primo, vetsi volnost pro obe strany kontraktu, nezavisle
zmeny
- komponenta v ruznem kontextu, testovani v izolaci
- dvě možné impementace
23. • Neinvazivnost
• Typy DI
• Metadata
• Reference mezi komponentami
• Řízení vzniku komponent
• Životní cyklus komponent
• Jednoduchá testovatelnost
Sunday 13 May 2012 23
základní charakteristika Spring IoC kontejneru
26. Neinvazivnost
• Bean == managovaný objekt
• POJO
• žádný marker interface
• final třídy
• param. konstruktory
Sunday 13 May 2012 26
27. Typy DI
• Constructor injection
• + Bezpečnější, Přehlednější
• - Nepovinné závislosti
• - Cyklické závislosti
• Setter injection
• + Nepovinné, velké množství závislosti
• - Chybějící závislosti
• Field injection
• + jednoduchý zápis
• - netrasparentní
Sunday 13 May 2012 27
Pro ruzné situace se hodi různé typy DI
28. Metadata pro popis
komponent
• Anotace
• + Jednoduchý zápis
• - Zapečené v kódu
• XML
• + Lze měnit v deploy time
• - Ukecané /
• Java kód
• + Flexibilní, refactor friendly
• - Zapečené v kódu
Sunday 13 May 2012 28
- v aplikace obvykle zastoupeny oba dva
typy
29. Reference mezi komponentami
• Typem
• Bezpečnější (teoreticky)
• Symbolickým jménem
• Více instancí stejného typu
• Variabilnější skládání
Sunday 13 May 2012 29
30. Řízení vzniku komponent
• Uvnitř kontextu
• Delegace
• Factory, Factory method
• Mimo kontext
• Deserializace komponenty
• Web či ORM framework
Sunday 13 May 2012 30
Legacy kod, 3rd party knihovny
32. Definice beany
<bean id="" class=""></bean>
• Jméno
• atribut id
• Typ
• atribut class
Sunday 13 May 2012 32
- jeden typ Nkrát
- jméno automaticky generovane
- id hlidane parserem
33. Reference(závislosti)
<bean id="" class="">
<property name="" ref=""/>
<property name="" value="" />
<constructor-arg ref="" value=""></constructor-arg>
</bean>
• Elm. property/constructor-arg
• Hodnota (value)
• Reference (name)
Sunday 13 May 2012 33
- v pripade value -Property Editor
- property/constructor-arg mozno kombinovat dohromady
- ridi kontejner
35. Good practice
• Jméno beany obsahuje jméno classy
• FooHooBar třída == fooHooBar beana
• Prefixujte jmena bean jejich typem či určením
• dao.FooHooBar, integration.FooHooBar
• V případě refaktoru názvu používejte alias
• Buďte defenzivní
• Inner beans
Sunday 13 May 2012 35
37. Méně ukecané XML
xmlns:p="http://www.springframework.org/schema/p"
<bean
id="myBean"
class="cz.sweb.MyBean"
p:dependencyA-ref="dependencyA"/>
Sunday 13 May 2012 37
38. Delegace vytváření instancí
• Factory
• Beana, která slouží k vyrábění
jiných bean
• Factory method
• Beana se statickou metodou,
která vyrábí instance sebe sama
Sunday 13 May 2012 38
39. Factory
<bean id="factory" class="Factory" />
<bean id="beanB"
factory-bean="factory"
factory-method="newInstance" />
public class Factory {
public MyBeanB newInstance() {
return new MyBeanB();
}
}
Sunday 13 May 2012 39
40. Factory method
<bean
id="myBeanA"
class="MyBeanA"
factory-method="newInstance"/>
public class MyBeanA {
public static MyBeanA newInstance() {
return new MyBeanA();
}
}
Sunday 13 May 2012 40
- factory method musi byt staticka
41. Init, Destroy, Lazy atd.
<bean class="Bean" init-method="myInit" destroy-method="myDestroy">
<property name="depedencies" value="foo" />
</bean>
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class Bean implements InitializingBean, DisposableBean{
public Bean() {} 1
public void setDepedencies(String foo) {} 2
public void afterPropertiesSet() throws Exception {} 3
public void myInit() {} 4
public void destroy() throws Exception {} 5
public void myDestroy(){} 6
}
Sunday 13 May 2012 41
- rozdilny lifecycle pro singleton a prototype
42. Poznámka na konto XML
• Občas ukecané Ale stále funkční ;-)
• Nejsilnější možnosti konfigurace
• DI (factory object|method
delegation)
• Spring container customization
• Dědičnost
• Inner beany
Sunday 13 May 2012 42
ukecanost - DI, transaction demarcation
44. 1.) Implementaci ReservationService a FileSystemBookStoreDao zaveďte jako
beany v XML.
2.) ReservationService dostane BookStoreDao implementaci
(FileSystemBookStoreDao) skrze konstruktor
3.) FileSystemBookStoreDao dostane cestu pro čtení a ukládání knih settrem
4.) Připravte in-memory implementaci BookStoreDao (MemoryBookStoreDao),
která bude číst/zapisovat do paměti resp. bude naimplementovaná nad
java.util.Map<Long, Book>. Mapa bude obsahovat jako klíč Long a jako
hodnotu Book. Mapu bude mozne nastavit do MemoryBookStoreDao settrem.
Pripravte test, ktery overi, ze metody getBook a saveBook.
5.) MemoryBookStoreDao bude mít init metodu, která vypíše předpřipravené
knihy
6.) MemoryBookStoreDao bude mít metodu destroy, která vyčistí mapu
7.) Zaveďte jednu knihu jako inner beanu do java.util.Map<Long, Book>,
ktera se pouzije pro konfiguraci beany MemoryBookStoreDao
8.) Do tridy Book pridejte factory metodou newBook()
9.) Upravte definici inner beany Book, aby se vytvarela factory metodou
10.) Priprave Factory, ktera bude vytvaret java.util.Map<Long, Book>
nahradte touto faktory puvodni beanu. Zachovejte vytvareni Book beany pres
jeji factory metodu newBook().
V kazdem kroku validujte vas postup testem ReservationServiceTest, ktery musi
prochazet.
Sunday 13 May 2012 44
- pokracovat v sandboxu, odkomentovat dependence
45. Jak otestovat
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:META-INF/<context-file-name>.xml"})
public class MyTest {
@Autowired
private MyBean bean;
@Test
public void testXXX() {
}
}
Sunday 13 May 2012 45
47. Definice beany
• Základní anotace na třídě
• @Component
• @Controller
• @Service
• @Repository
• nepovinný atribut value (id)
Sunday 13 May 2012 47
- component (genericka), controller (web), service (business logika), repository (DAO)
- Repository, automaticky preklad vyjimek pokud pracujeme primo JDBC, Session atd.
48. Reference(závislosti)
• Základní anotace
• @Autowired
• field, metoda, konstruktor
• @Qualifier
• jemný výběr např. jménem
Sunday 13 May 2012 48
- narozdil od XML a settrum moznost definovat na libovolne metode
- @Autowired definuje required attribute pro volitelne zavislosti
- @Autowired nelze pouzit pro injectovani generickych typu, @Resourc anotace musi byt
pouzita namisto ni
49. @Component
public class Bean {
@Autowired(required=false)
private OtherBean something;
private final Hoo hoo;
@Autowired
public Bean(@Qualifier(value="hoo") Hoo hoo) {
this.hoo = hoo;
}
@Autowired
public void setX(String x) {
}
}
Sunday 13 May 2012 49
50. Component scanning
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="cz.sweb.pichlik"/>
</beans>
• Stále potřebujeme XML
• Aktivace anotací
• Kde hledat anotované třídy
Sunday 13 May 2012 50
51. Autowiring
• Skládání objektů podle jejich
závislostí
• @Autowired
• Řízený typem (volitelně jménem)
Sunday 13 May 2012 51
- autowiring funguje rovnez v XML
52. Co je potřeba vzít v potaz
Sunday 13 May 2012 52
- autowiring funguje typem by default
53. Předcházíme problémům
• Buďte defenzivní
• @Autowired + @Qualifier
• Použití specifičtějšího typu
Sunday 13 May 2012 53
- pouziti specifickeho typu muze selhat ve chvili proxy modu napr. anotace
55. Poznámka na konto anotací
• + Méně ukecané
• Definici beany
• Závislosti
• Transakce
• - pouze jedna instance od každé
třídy
• - magické díky autowiringu
Sunday 13 May 2012 55
57. 1.) Beany ReservationService a MemoryBookStoreDao zavedte pomoci
anotaci
2.) Pouijte anotace pro volani init a destroy metody na
MemoryBookStoreDao
3.) java.util.Map<Long, Book> zavedte jmenem a pomoci anotace
Resource (Autowired nebude fungovat)
4.) Upravte definici ReservationService, aby se vzdy pouzila
implementace MemoryBookStoreDao
V kazdem kroku validujte vas postup testem ReservationServiceTest,
ktery musi prochazet.
Sunday 13 May 2012 57
62. Request, Session
Proxy Singleton
Sunday 13 May 2012 62
- zmena scope je vzdy problem (singleton vs. scope)
- http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-
method-injection
63. Definice
• XML
• atribut scope
• Anotace
• @Scope(value="...")
Sunday 13 May 2012 63
65. 1.) Upravte definici beany Book, aby mela scope prototype
2.) Upravte definici beany java.util.Map<Long, Book>, aby pod dvema
ruznymi klici referencovala beanu Book
3.) Pripravte test, ktery overi, ze List skutecne obsahuje ruzne instance
beany Book
4.) Zmente scope prototype na singleton
5.) Overte testem, ze List obsahuje jednu a tu samou instanci objektu Book
Sunday 13 May 2012 65
67. Java Based Config
• Mix anotací a Java kódu
• Alternativa k XML
• @Configuration
• @Bean
• name, init, destroy, autowire
• @Import
Sunday 13 May 2012 67
- lze kombinovat XML, Anotace i Java Based config
- vhodné pro případy kdy v XML máme pouze deployment specifické beany a zbytek chceme
mít v kódu
- k init, destroy lze používat jako alternativu JSR-250 anotace
68. <beans ...>
<bean class="cz.sweb.pichlik.springioc.javaconfig.ConfigClass" /> zavedení configu
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/> @Configuration
<property name="username" value="${jdbc.username}"/> public class ConfigClass {
<property name="password" value="${jdbc.password}"/>
</bean>
</beans> @Autowired
private DataSource dataSource;
definice beany @Bean()
public MyService configureMyservice(){
return new MyService(configureJdbcDao());
}
dependency
injection
public class MyService {
@Bean()
public JdbcDao configureJdbcDao() {
private final DaoInterface daoInterface;
return new JdbcDao(dataSource);
}
public MyService(DaoInterface daoInterface) {
super();
@Bean()
this.daoInterface = daoInterface;
public HibernateDao configureHiberDao() {
}
return new HibernateDao(dataSource);
}
}
}
Sunday 13 May 2012 68
autowiring funguje viz DataSource beana
69. Jak to funguje
@Configuration
• JavaConfig třídy jsou public class ConfigClass {
dynamicky rozšířeny
@Autowired
private DataSource dataSource;
• CGLIB @Bean()
public MyService configureMyservice(){
return new MyService(configureJdbcDao());
}
• volání
@Bean()
configureJdbcDao jde public JdbcDao configureJdbcDao() {
přes proxy IoC kontejneru return new JdbcDao(dataSource);
}
@Bean()
• scopes public HibernateDao configureHiberDao() {
return new HibernateDao(dataSource);
}
}
• postprocessing
• autowiring
Sunday 13 May 2012 69
70. Zavedení JavaConfig tříd
• Třídy anotované @Configuration
• Tři způsoby zavedení JavaConfigu
• Klasická beana v XML
• Beana na scanované classpath
• Programově
• new AnnotationConfigApplicationContext(ConfigClass.class)
Sunday 13 May 2012 70
72. 1.) Pripravte JavaConfig beanu pomoci anotaci, ktery bude zavadet
beanu MemoryBookStoreDao. Z tridy MemoryBookStoreDao
odstrante vsechny anotace.
2.) Zajistete deklarativne volani (nevolejte primo) init a destroy metody
na MemoryBookStoreDao
3.) Beanu reprezentujici java.util.Map<Long, Book> si nechte
nainjectovat do bean JavaConfig pres setter
V kazdem kroku validujte vas postup testem ReservationServiceTest,
ktery musi prochazet.
Sunday 13 May 2012 72