Nebolo by skvelé, keby sme vedeli konfigurovať springácke beany tak, že hodnoty ich inštančných premenných sa natiahnu z properties
súboru?
Napr. mám úžasnú triedu pre “aplikáciu”:
package sk.upjs.ics.novotnyr;
public class ApplicationBean {
private int version;
private String title;
private boolean deployedOnCloud;
public int getVersion() {
return version;
}
public String getTitle() {
return title;
}
public boolean isDeployedOnCloud() {
return deployedOnCloud;
}
@Override
public String toString() {
return "ApplicationBean [version=" + version + ", title=" + title
+ ", deployedOnCloud=" + deployedOnCloud + "]";
}
}
Atribúty version
, title
a deployedOnCloud
by sa mohli automaticky načítať z properties
súboru application.properties
, ktorý vyzerá nasledovne:
app.version=1
app.title=Spring Test
app.deployedOnCloud=true
V bežnej aplikácii by to znamenalo kadejaké načítavanie properties, riešenie problémov s jeho umiestnením, a kadečo.
V Springu je to ízy
Anotácie triedy
Stačí anotovať bean ako springácky @Component
a využiť ďalšiu fintivú anotáciu @Value
. Tá umožňuje nastavovať hodnoty inštančným premenným na základe pestrých pravidiel.
package sk.upjs.ics.novotnyr;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class ApplicationBean {
@Value("${app.version}")
private int version;
@Value("${app.title}")
private String title;
@Value("${app.deployedOnCloud}")
private boolean deployedOnCloud;
public int getVersion() {
return version;
}
public String getTitle() {
return title;
}
public boolean isDeployedOnCloud() {
return deployedOnCloud;
}
@Override
public String toString() {
return "ApplicationBean [version=" + version + ", title=" + title
+ ", deployedOnCloud=" + deployedOnCloud + "]";
}
}
Každá inštančná premenná vyfasovala svoju vlastnú @Value
s parametrom. Jeho hodnota je v tvare známom z make
/ant
ovských premenných. Napr. ${app.version}
sa má vyhodnotiť na hodnotu premennej app.version
. Všimnite si, ako sa jej názov zhoduje s názvom kľúča v properties
súbore.
Nastavenie aplikačného kontextu
Teraz treba presvedčiť Spring, aby vedel, že “tieto hodnoty” sa načítajú “z tohto súboru.”
Vyrieši sa to jedným riadkom v súbore aplikačného kontextu. Stačí zapnúť automatické vyhodnocovanie propertoidných premenných:
<context:property-placeholder location="classpath:/sk/upjs/ics/novotnyr/application.properties"/>
Tento element priamo umožňuje nastaviť cestu k properties
súboru pomocou repertoáru springovských resources. V tomto príklade sa súbor application.properties
nachádza v CLASSPATH
e hneď vedľa triedy.
Mimochodom, budeme predpokladať automatické vyhľadávanie beanov a ich registráciu v springáckom kontexte, čo rieši element <context:component-scan>
.
Celý applicationContext.xml
vyzerá:
<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:util="http://www.springframework.org/schema/util"
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-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
">
<context:component-scan base-package="sk.upjs.ics.novotnyr" />
<context:property-placeholder location="classpath:/sk/upjs/ics/novotnyr/application.properties"/>
</beans>
Konfigurák môžeme tiež buchnúť vedľa triedy ApplicationBean
.
Test!
Celé to môžeme rozbehnúť takto:
package sk.upjs.ics.novotnyr;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml", SpringTest.class);
ApplicationBean bean = ctx.getBean(ApplicationBean.class);
System.out.println(bean);
}
}
A hľa! Výstupom bude (po ignorovaní inicializácie Springu):
ApplicationBean [version=1, title=Spring Test, deployedOnCloud=true]
Čo s chýbajúcimi hodnotami?
Niekedy sa stane, že názov premennej uvedenej v ${...}
sa jednoducho nenájde. Skúste si uviesť napr. toto:
@Value("${title}")
private String title;
Ak spustíte test, celé to zhavaruje s tonou výnimiek, kde prapôvodná príčina jest:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'version' in string value [${title}]
Jedno z riešení je použiť implicitné hodnoty, ktoré možno uviesť za dvojbodku:
@Value("${app.title:N/A}")
private String title;
Ak sa náhodou nenájde premenná s názvom app.title
, dosadí sa za ňu implicitná hodnota, v tomto prípade “N/A”.
Bonusovka na záver
Celé správanie je v skutočnosti v zodpovednosti triedy org.springframework.beans.factory.config.PropertyPlaceholderConfigurer. Tá je v Springu od nepamäti (teda pokiaľ nepamäť siaha do roku 2003).