54
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 . Tuesday 28 May 13

Spring ioc-advanced

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Spring ioc-advanced

Spring frameworkMotto: 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.

Tuesday 28 May 13

Page 2: Spring ioc-advanced

IoC containerAdvanced

Tuesday 28 May 13

Page 3: Spring ioc-advanced

Agenda

• Hierarchická konfigurace

• Dynamické nahrávání kontextů

• PropertyEditory

• Validace

• SPEL

Tuesday 28 May 13

Page 4: Spring ioc-advanced

Konfigurace na druhou

Tuesday 28 May 13

Page 5: Spring ioc-advanced

Properties

Tuesday 28 May 13

Page 6: Spring ioc-advanced

Property placeholders

• Konfigurace mimo XML

• Atributy spjaté s prostředím

• databáze, HTTP endpointy atd.

• známe až v deploy time

Tuesday 28 May 13

- Operations opravdu neradi editují XML v zanorenem JARu na filesystemu

Page 7: Spring ioc-advanced

Příklad

@Componentpublic class MyAnnotatedBean {

@Value("${username}") private String username;

public String getUsername() { return username; }}

Tuesday 28 May 13

Page 8: Spring ioc-advanced

Složitější případ užití

• Proč jeden soubor nestačí

• různá prostředí

• testy, produkce, developer stroj

• chceme definovat smart defaults

Tuesday 28 May 13

Page 9: Spring ioc-advanced

Konfigurační hierarchie

• Každá komponenta může definovat default hodnoty

• Aplikace definuje svoje default hodnoty

• Prostředí definuje svoje hodnoty

Component defaults

Application defaults

Environment values

přep

isuje

Tuesday 28 May 13

System.properties override

Page 10: Spring ioc-advanced

Provedení

• Pořadí definice určuje prioritu

• Dynamické načítání z classpath

• Chybějící properties soubory se ignorují

• přenositelnost

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="ignoreResourceNotFound" value="true" /> <property name="ignoreUnresolvablePlaceholders" value="true" /> <property name="locations"> <list> <value>classpath*:META-INF/componentDefault.properties</value> <value>classpath:META-INF/applicationDefault.properties</value> <value>file:/opt/configuration/deployment.properties</value> </list> </property></bean>

Tuesday 28 May 13

Page 11: Spring ioc-advanced

Resource abstrakce

Tuesday 28 May 13

Page 12: Spring ioc-advanced

Resource• Spring abstrakce pro přístup k

souborům v různém prostředí

Prefix Příklad Vysvětlivkaclasspath: classpath:com/myapp/config.xml Nahravá se z classpath

file: file:/data/config.xml Nahrává se z FShttp: http://myserver/logo.png Nahrává přes URL

Bez prefixu /data/config.xml Závisí na typu ApplicationContext

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");

<bean id="myBean" class="..."> <property name="template" value="some/resource/path/myTemplate.txt"/></bean>

Tuesday 28 May 13

Page 13: Spring ioc-advanced

Wildcards & Ant path

/WEB-INF/*-context.xmlclasspath:com/mycompany/**/applicationContext.xmlclasspath*:META-INF/*-beans.xml

• Wildcard *

• nahrání více resourců

• komplexní boot aplikace

Tuesday 28 May 13

Page 14: Spring ioc-advanced

Dynamické sestavení kontextu

Tuesday 28 May 13

Page 15: Spring ioc-advanced

Motivace

• Pouze ze začátku vystačí jeden bean definition file na aplikace

• nepraktické

• chceme oddělit definici bean podle komponenty nebo typu

• přehlednost

Tuesday 28 May 13

Page 16: Spring ioc-advanced

Využití Resource abstrakce

• Definujte kontexty v předem definované cestě

• META-INF/company/spring

• Pojmenované s pevným suffixem

• *-applicationContext.xml

Tuesday 28 May 13

Page 17: Spring ioc-advanced

Inicializace• Automatické načtení všech

bean definic na classpath

• usnadňuje přidávání nových kontextů

• umožňuje dynamické načítání podle toho jak je classpath sestavena

• někdy méně přehledné

String path = "classpath*:META-INF/company/*-applicationContext.xml";new ClassPathXmlApplicationContext(path);

<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:META-INF/company/*-applicationContext.xml </param-value></context-param>

Tuesday 28 May 13

Page 18: Spring ioc-advanced

Strategický context

• Definuje infrastrukturní beany používané v celé aplikaci

• DataSource, Transakční manažer, HibernateSessionFactory atd.

• Může mít různou podobu pro různá prostředí

• Testy, Produkce, Aplikační server

Tuesday 28 May 13

- nejdulezitejsi beany na jednom miste- lze pouzit import

Page 19: Spring ioc-advanced

PropertyEditors

Tuesday 28 May 13

Page 20: Spring ioc-advanced

java.beans.PropertyEditor

• Rozhraní pro konverzi String –> Datový typ ve Springu

• Používá se

• inicializace kontejneru a nastavování bean values

• Spring MVC konverze z query params (?name=dagi&age=31)

Tuesday 28 May 13

Page 21: Spring ioc-advanced

public class BeanWithSpecialDate {

private SpecialDateType specialDateType;

public SpecialDateType getSpecialDateType() { return specialDateType; }

public void setSpecialDateType(SpecialDateType specialDateType) { this.specialDateType = specialDateType; }}

public class SpecialDateType { private final Date date;

public SpecialDateType(Date date) { this.date = date; }

public Date getDate() { return date; }}

public class SpecialDatePropertyEditor extends PropertyEditorSupport{

@Override public void setAsText(String text) throws IllegalArgumentException { SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); try { setValue(new SpecialDateType(sdf.parse(text))); } catch (ParseException e) { throw new IllegalArgumentException("Cannot parse date", e); } }}

<bean class="cz.sweb.pichlik.springioc.propertyeditor.BeanWithSpecialDate"> <property name="specialDateType" value="01-01-2000" /></bean> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="cz.sweb.pichlik.springioc.propertyeditor.SpecialDateType" value="cz.sweb.pichlik.springioc.propertyeditor.SpecialDatePropertyEditor"/> </map> </property></bean>

je definovaná

se sp

eciá

lním

type

m uvedeným jako String

Tuesday 28 May 13

Page 22: Spring ioc-advanced

public class BeanWithSpecialDate {

private SpecialDateType specialDateType;

public SpecialDateType getSpecialDateType() { return specialDateType; }

public void setSpecialDateType(SpecialDateType specialDateType) { this.specialDateType = specialDateType; }}

public class SpecialDateType { private final Date date;

public SpecialDateType(Date date) { this.date = date; }

public Date getDate() { return date; }}

public class SpecialDatePropertyEditor extends PropertyEditorSupport{

@Override public void setAsText(String text) throws IllegalArgumentException { SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); try { setValue(new SpecialDateType(sdf.parse(text))); } catch (ParseException e) { throw new IllegalArgumentException("Cannot parse date", e); } }}

<bean class="cz.sweb.pichlik.springioc.propertyeditor.BeanWithSpecialDate"> <property name="specialDateType" value="01-01-2000" /></bean> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="cz.sweb.pichlik.springioc.propertyeditor.SpecialDateType" value="cz.sweb.pichlik.springioc.propertyeditor.SpecialDatePropertyEditor"/> </map> </property></bean>

o jehož konverzi se stará PropertyEditor

Tuesday 28 May 13

Page 23: Spring ioc-advanced

public class BeanWithSpecialDate {

private SpecialDateType specialDateType;

public SpecialDateType getSpecialDateType() { return specialDateType; }

public void setSpecialDateType(SpecialDateType specialDateType) { this.specialDateType = specialDateType; }}

public class SpecialDateType { private final Date date;

public SpecialDateType(Date date) { this.date = date; }

public Date getDate() { return date; }}

public class SpecialDatePropertyEditor extends PropertyEditorSupport{

@Override public void setAsText(String text) throws IllegalArgumentException { SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); try { setValue(new SpecialDateType(sdf.parse(text))); } catch (ParseException e) { throw new IllegalArgumentException("Cannot parse date", e); } }}

<bean class="cz.sweb.pichlik.springioc.propertyeditor.BeanWithSpecialDate"> <property name="specialDateType" value="01-01-2000" /></bean> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="cz.sweb.pichlik.springioc.propertyeditor.SpecialDateType" value="cz.sweb.pichlik.springioc.propertyeditor.SpecialDatePropertyEditor"/> </map> </property></bean>

patřičně

zaregistr

ovaný

Tuesday 28 May 13

Page 24: Spring ioc-advanced

public class BeanWithSpecialDate {

private SpecialDateType specialDateType;

public SpecialDateType getSpecialDateType() { return specialDateType; }

public void setSpecialDateType(SpecialDateType specialDateType) { this.specialDateType = specialDateType; }}

public class SpecialDateType { private final Date date;

public SpecialDateType(Date date) { this.date = date; }

public Date getDate() { return date; }}

public class SpecialDatePropertyEditor extends PropertyEditorSupport{

@Override public void setAsText(String text) throws IllegalArgumentException { SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); try { setValue(new SpecialDateType(sdf.parse(text))); } catch (ParseException e) { throw new IllegalArgumentException("Cannot parse date", e); } }}

<bean class="cz.sweb.pichlik.springioc.propertyeditor.BeanWithSpecialDate"> <property name="specialDateType" value="01-01-2000" /></bean> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="cz.sweb.pichlik.springioc.propertyeditor.SpecialDateType" value="cz.sweb.pichlik.springioc.propertyeditor.SpecialDatePropertyEditor"/> </map> </property></bean>

je definovaná

se sp

eciá

lním

type

m uvedeným jako String

o jehož konverzi se stará PropertyEditor

patřičně

zaregistr

ovaný

Tuesday 28 May 13

Page 25: Spring ioc-advanced

Validate

Tuesday 28 May 13

Page 26: Spring ioc-advanced

• Řešeno přes Bean Validation

• JSR 303

• Možnost použití přes různé int.• org.springframework.validation

• javax.validation.Validator

• Integrace do Spring MVC

Tuesday 28 May 13

Page 27: Spring ioc-advanced

@Servicepublic class MyService {

@Autowired private Validator validator;

public void doSomethingWithPerson(Person person){ Set<ConstraintViolation<Person>> resultOfValidation = validator.validate(person); for (ConstraintViolation<Person> constraintViolation : resultOfValidation) { throw new IllegalArgumentException(constraintViolation.getMessage()); } }}

public class Person {

@DecimalMax(value="110", message="Maximum age is 110") @DecimalMin(value="0", message="Minimum age is 0") private int age;

@NotNull @Valid private Address address;

public Person() { super(); }

public Person(int age, Address address) { super(); this.age = age; this.address = address; }}

<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

použ

ívá

valid

átor

validuje

JSR 303 validační anotace

Tuesday 28 May 13

Page 28: Spring ioc-advanced

SPEL

Tuesday 28 May 13

Page 29: Spring ioc-advanced

Spring EL

• Expression Language

• operátory, volání metod, proměnné a mnohem víc

• přímé použití jako EL

• definice bean

Tuesday 28 May 13

Page 30: Spring ioc-advanced

Použití• Jako EL ve vlastní aplikaci

• V rámcí definice bean

• Lze použít i v anotaci @Value

ExpressionParser p = new SpelExpressionParser();Expression exp = p.parseExpression("'Hello World'.concat('!')");String message = (String) exp.getValue();

<bean id="numberGuess" class="org.spring.samples.NumberGuess"> <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/></bean>

Tuesday 28 May 13

používání v definici bean vede k programování na úrovni XML => Ant syndrom

Page 31: Spring ioc-advanced

Vhodné použití• Enums, Constanty v XML

<bean class="cz.sweb.pichlik.springioc.spel.ColorBean"> <property name="color" value="#{ T(cz.sweb.pichlik.springioc.spel.Color).RED}" /> </bean>

Tuesday 28 May 13

Page 32: Spring ioc-advanced

IoC zbytek

Tuesday 28 May 13

Page 33: Spring ioc-advanced

Dědičnost

Tuesday 28 May 13

- sdileni definice vlastností mezi vice beanamy- nemá nic společného s objektovou hierarchií- společné property je možné přepsat v konkrétní beane

Page 34: Spring ioc-advanced

Integrace s existujícím kódem

Tuesday 28 May 13

Page 35: Spring ioc-advanced

Bean collecting

• “Sběr” objektů určitého typu

• Světlá strana autowiringu

Tuesday 28 May 13

- umoznuje dosahovat dynamicke extensibility aplikace- podpora XML i anotaci

Page 36: Spring ioc-advanced

Anotace @Required

• Hlídá nastavení závislostí

• využití v kombinaci s XMLpublic class Bean {

private String foo;

@Required public void setFoo(String foo) { this.foo = foo; } }

<bean class="Bean"> <!-- Missing declaration foo property --></bean>

Tuesday 28 May 13

- predchazi NPE, kontainter selze pri bootu na chybejici zavislost

Page 37: Spring ioc-advanced

Nepřímé závislosti

Tuesday 28 May 13

- 3rd party nebo legacy kod- pouzivat obezretne (v kodu neco smrdi)

Page 38: Spring ioc-advanced

Cyklické závislosti

• Vyvarujte se jich

• Špatný návrh API

• IoC kontejner dokáže částečně řešit

Tuesday 28 May 13

- fakci pouze pro setter injection

Page 39: Spring ioc-advanced

Profily

Tuesday 28 May 13

Page 40: Spring ioc-advanced

Spring Bean Definition profiles

• Bean definition might be defined in a context activated on demand

• Context may represent an environment or a strategy

• Multiple profiles might be activated

Tuesday 28 May 13

Page 41: Spring ioc-advanced

Real/Mock example ... <beans profile="real-backends"> <mongo:mongo id="mongo" replica-set="${mongodb.replicaSet}"> <mongo:options connect-timeout="${mongodb.connectTimeout}" socket-timeout="${mongodb.socketTimeout}" write-timeout="${mongodb.writeTimeout}" write-number="${mongodb.writeNumber}" auto-connect-retry="true" socket-keep-alive="true" /> </mongo:mongo> </beans>

<beans profile="mocked-backends"> <bean id="mongo" class="com.mongodb.Mongo" factory-bean="fongo" factory-method="getMongo"/> <bean id="fongo" class="com.foursquare.fongo.Fongo"> <constructor-arg value="gdc"></constructor-arg> </bean> </beans>

Tuesday 28 May 13

Page 42: Spring ioc-advanced

Profile servlet aktivace

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

...

<!-- Activate profile with real-backends. This profile contains beans configured against the real backend and not mocks. The profile might be changed during integration tests where mocked backends are used. --> <context-param> <param-name>spring.profiles.default</param-name> <param-value>real-backends</param-value> </context-param>

...

Tuesday 28 May 13

Page 43: Spring ioc-advanced

Profile aktivace v int. test

/** * Common superclass for integration tests. This class turns on mocked backends. */public abstract class AbstractWebappIntegrationTest extends AbstractIntegrationTest { ...

private static final String MOCKED_BACKENDS_PROFILE_NAME = "mocked-backends";

/** * Activates profile with mocked */ @BeforeClass public static final void activateMockedBackends(){ log.warn("Activating profile with mocked backends '{}'", MOCKED_BACKENDS_PROFILE_NAME); System.setProperty("spring.profiles.active", MOCKED_BACKENDS_PROFILE_NAME); }

...}

Tuesday 28 May 13

Page 44: Spring ioc-advanced

Aktivace profilu

• Context ini param in web.xml• spring.profiles.default

• spring.profiles.active

• Programmatically• ConfigurableEnvironment.setActiveProfiles()

• System property• spring.profiles.active

Tuesday 28 May 13

Page 45: Spring ioc-advanced

Profile gotchas

• Musí být definován na konci XML souboru

• Beany nejsou ani parsovány pokud není profil aktivní

• Profil default může být použit jako výchozí

• Alternativa k spring.profiles.defaultTuesday 28 May 13

Může vést k tomu, že pokud není profil zapnutý, nevíme jestli je vůbec daná část XML správně

Page 47: Spring ioc-advanced

Praktické cvičení

Tuesday 28 May 13

Page 48: Spring ioc-advanced

1.) Nadefinujte nekolik bean Book v XML2.) Upravte implementaci MemoryBookStoreDao, aby se automaticky sebraly beany typu Book do Listu3.) Presunte konfiguraci cesty pro FileSystemBookStoreDao do Properties souboru4.) Overte testem, ze obe implementace MemoryBookStoreDao po teto zmene funguji

Ukazka - autowiringu na objektech, ktere nejsou beany

Tuesday 28 May 13

Page 49: Spring ioc-advanced

Čeho se vyvarovat

Tuesday 28 May 13

Page 50: Spring ioc-advanced

Programový bean lookup

• Používat velice obezřetně!

• Uvnitř bean speciálně

• NPE

• Nepřímé závislosti

Tuesday 28 May 13

- pouze mimo IoC kontext- prakticke opodstatneni legacy kod a nebo problem singleton vs. prototyp

Page 51: Spring ioc-advanced

Statické holdery

• Funguje jenom pro singleton beany

• Znemožňuje reload instance

Tuesday 28 May 13

Page 52: Spring ioc-advanced

Vykutálený pomocník

• Musí být inicializován jako první

• Obchází DI

• WebApplicationContextUtilsTuesday 28 May 13

Page 53: Spring ioc-advanced

Závěrečná doporučení

Tuesday 28 May 13

Page 54: Spring ioc-advanced

• Předejděte náhodnému mixování XML a anotací

• Používejte @Qualifier pokud si nejste jistí

• V případě XML použijte @Required

• Nepoužívejte programový lookup bean pokud to neni nezbytně nutné

• Pozor na mixování singleton a prototype scope

Tuesday 28 May 13