Spring framework
Motto: Musíterozbí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
Property placeholders
• Konfiguracemimo 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
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
9.
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řepisuje
Tuesday 28 May 13
System.properties override
10.
Provedení
• Pořadí definiceurč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
Resource
• Spring abstrakcepro přístup k
souborům v různém prostředí
Prefix Příklad Vysvětlivka
classpath: classpath:com/myapp/config.xml Nahravá se z classpath
file: file:/data/config.xml Nahrává se z FS
http: 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
13.
Wildcards & Antpath
/WEB-INF/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
classpath*:META-INF/*-beans.xml
• Wildcard *
• nahrání více resourců
• komplexní boot aplikace
Tuesday 28 May 13
Motivace
• Pouze zezačátku vystačí jeden
bean definition file na aplikace
• nepraktické
• chceme oddělit definici bean
podle komponenty nebo typu
• přehlednost
Tuesday 28 May 13
16.
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
17.
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
18.
Strategický context
• Definujeinfrastrukturní 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
java.beans.PropertyEditor
• Rozhraní prokonverzi 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
21.
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á
sespeciálním
typem
uvedeným jako String
Tuesday 28 May 13
22.
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
23.
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ě zaregistrovaný
Tuesday 28 May 13
24.
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á
sespeciálním
typem
uvedeným jako String
o jehož konverzi se stará PropertyEditor
patřičně zaregistrovaný
Tuesday 28 May 13
• Řešeno přesBean 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
27.
@Service
public 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
Spring EL
• ExpressionLanguage
• operátory, volání metod,
proměnné a mnohem víc
• přímé použití jako EL
• definice bean
Tuesday 28 May 13
30.
Použití
• Jako ELve 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
31.
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
Dědičnost
Tuesday 28 May13
- 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
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
36.
Anotace @Required
• Hlídánastavení závislostí
• využití v kombinaci s XML
public 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
Spring Bean Definitionprofiles
• 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
Profile servlet aktivace
<web-appversion="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
43.
Profile aktivace vint. 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
44.
Aktivace profilu
• Contextini param in web.xml
• spring.profiles.default
• spring.profiles.active
• Programmatically
• ConfigurableEnvironment.setActiveProfiles()
• System property
• spring.profiles.active
Tuesday 28 May 13
45.
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.default
Tuesday 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ě
46.
Více o profilech
•http://blog.springsource.com/
2011/02/11/spring-
framework-3-1-m1-released/
• http://blog.springsource.org/
2011/02/14/spring-3-1-m1-
introducing-profile/
Tuesday 28 May 13
1.) Nadefinujte nekolikbean Book v XML
2.) Upravte implementaci MemoryBookStoreDao, aby se automaticky
sebraly beany typu Book do Listu
3.) Presunte konfiguraci cesty pro FileSystemBookStoreDao do Properties
souboru
4.) Overte testem, ze obe implementace MemoryBookStoreDao po teto
zmene funguji
Ukazka - autowiringu na objektech, ktere nejsou beany
Tuesday 28 May 13
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
• Předejděte náhodnémumixová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