Eigenschappen met Spring en Spring Boot

1. Overzicht

Deze tutorial zal laten zien hoe u eigenschappen instelt en gebruikt in het voorjaar via Java-configuratie en @PropertySource.

We zullen ook zien hoe eigenschappen werken in Spring Boot.

2. Registreer een eigenschappenbestand via Annotaties

Spring 3.1 introduceert ook de nieuwe @PropertySource annotatie als een handig mechanisme om eigendomsbronnen aan de omgeving toe te voegen.

We kunnen deze annotatie gebruiken in combinatie met de @Configuratie annotatie:

@Configuration @PropertySource ("classpath: foo.properties") openbare klasse PropertiesWithJavaConfig {// ...}

Een andere zeer handige manier om een ​​nieuw eigenschappenbestand te registreren, is door een tijdelijke aanduiding te gebruiken, wat ons in staat stelt selecteer dynamisch het juiste bestand tijdens runtime:

@PropertySource ({"classpath: persistence - $ {envTarget: mysql} .properties"}) ...

2.1. Meerdere eigendomslocaties definiëren

De @PropertySource annotatie is herhaalbaar volgens de Java 8-conventies. Als we Java 8 of hoger gebruiken, kunnen we daarom deze annotatie gebruiken om meerdere propertylocaties te definiëren:

@PropertySource ("classpath: foo.properties") @PropertySource ("classpath: bar.properties") openbare klasse PropertiesWithJavaConfig {// ...}

Natuurlijk, we kunnen ook de @PropertySources annotatie en specificeer een array van @PropertySource. Dit werkt in elke ondersteunde Java-versie, niet alleen in Java 8 of hoger:

@PropertySources ({@PropertySource ("classpath: foo.properties"), @PropertySource ("classpath: bar.properties")}) openbare klasse PropertiesWithJavaConfig {// ...}

In beide gevallen is het vermeldenswaard dat in het geval van een botsing van de eigenschapsnaam, de laatst gelezen bron voorrang heeft.

3. Eigenschappen gebruiken / injecteren

Een eigenschap injecteren met de @Waarde annotatie is eenvoudig:

@Value ("$ {jdbc.url}") private String jdbcUrl;

We kunnen ook een standaardwaarde voor de eigenschap specificeren:

@Value ("$ {jdbc.url: aDefaultUrl}") private String jdbcUrl;

De nieuwe PropertySourcesPlaceholderConfigurer toegevoegd in Spring 3.1 los $ {…} tijdelijke aanduidingen op binnen de eigenschapswaarden van bean-definitie en @Waarde annotaties.

Eindelijk kunnen we verkrijg de waarde van een eigenschap met behulp van de Milieu API:

@Autowired privéomgeving env; ... dataSource.setUrl (env.getProperty ("jdbc.url"));

4. Eigenschappen met Spring Boot

Voordat we ingaan op meer geavanceerde configuratie-opties voor eigenschappen, laten we wat tijd besteden aan het bekijken van de nieuwe eigenschappenondersteuning in Spring Boot.

In het algemeen, deze nieuwe ondersteuning vereist minder configuratie in vergelijking met standaard Spring, wat natuurlijk een van de hoofddoelen van Boot is.

4.1. application.properties: het standaardeigenschappenbestand

Boot past zijn typische conventie over configuratiebenadering toe op eigenschappenbestanden. Dit betekent dat we kunnen gewoon een application.properties bestand in ons src / main / resources directory, en het zal automatisch worden gedetecteerd. We kunnen er dan normaal geladen eigenschappen uit injecteren.

Door dit standaardbestand te gebruiken, hoeven we dus niet expliciet een PropertySource of geef zelfs een pad naar een eigenschappenbestand op.

We kunnen ook tijdens runtime een ander bestand configureren als dat nodig is, met behulp van een omgevingseigenschap:

java -jar app.jar --spring.config.location = classpath: /another-location.properties

Vanaf Spring Boot 2.3, we kunnen ook jokertekens specificeren voor configuratiebestanden.

We kunnen bijvoorbeeld de spring.config.location eigendom aan config / * /:

java -jar app.jar --spring.config.location = config / * /

Op deze manier zoekt Spring Boot naar configuratiebestanden die overeenkomen met het config / * / directorypatroon buiten ons jar-bestand. Dit is handig als we meerdere bronnen met configuratie-eigenschappen hebben.

Sinds versie 2.4.0, Spring Boot ondersteunt het gebruik van eigenschappenbestanden voor meerdere documenten, net zoals YAML dat doet bij ontwerp:

baeldung.customProperty = defaultValue # --- baeldung.customProperty = overschrevenValue

Merk op dat voor eigenschappenbestanden de notatie met drie streepjes wordt voorafgegaan door een commentaarteken (#).

4.2. Omgevingsspecifiek eigenschappenbestand

Als we ons op verschillende omgevingen moeten richten, is daar een ingebouwd mechanisme voor in Boot.

We kunnen eenvoudig een toepassingsomgeving.eigenschappen bestand in het src / main / resources directory en stel vervolgens een Spring-profiel in met dezelfde omgevingsnaam.

Als we bijvoorbeeld een 'staging'-omgeving definiëren, betekent dit dat we een enscenering profiel en dan application-staging.properties.

Dit env-bestand wordt geladen en heeft voorrang op het standaard eigenschappenbestand. Merk op dat het standaardbestand nog steeds wordt geladen, het is alleen dat wanneer er een botsing van eigenschappen is, het omgevingsspecifieke eigenschappenbestand voorrang heeft.

4.3. Testspecifiek eigenschappenbestand

Mogelijk hebben we ook de vereiste om verschillende eigenschapswaarden te gebruiken wanneer onze applicatie wordt getest.

Spring Boot regelt dit voor ons door in ons te kijken src / test / resources directory tijdens een testrun. Nogmaals, de standaardeigenschappen zullen nog steeds normaal injecteerbaar zijn, maar zullen hierdoor worden overschreven als er een botsing is.

4.4. De @TestPropertySource Annotatie

Als we meer gedetailleerde controle over testeigenschappen nodig hebben, kunnen we de @TestPropertySource annotatie.

Dit stelt ons in staat om testeigenschappen in te stellen voor een specifieke testcontext, waarbij voorrang wordt gegeven op de standaard eigenschapbronnen:

@RunWith (SpringRunner.class) @TestPropertySource ("/ foo.properties") openbare klasse FilePropertyInjectionUnitTest {@Value ("$ {foo}") private String foo; @Test openbare leegte whenFilePropertyProvided_thenProperlyInjected () {assertThat (foo) .isEqualTo ("bar"); }}

Als we een bestand niet willen gebruiken, kunnen we namen en waarden rechtstreeks specificeren:

@RunWith (SpringRunner.class) @TestPropertySource (properties = {"foo = bar"}) openbare klasse PropertyInjectionUnitTest {@Value ("$ {foo}") private String foo; @Test openbare leegte whenPropertyProvided_thenProperlyInjected () {assertThat (foo) .isEqualTo ("bar"); }}

We kunnen ook een soortgelijk effect bereiken met de eigendommen argument van de @BuienRadarNL annotatie:

@RunWith (SpringRunner.class) @SpringBootTest (properties = {"foo = bar"}, classes = SpringBootPropertiesTestApplication.class) openbare klasse SpringBootPropertyInjectionIntegrationTest {@Value ("$ {foo}") private String foo; @Test openbare leegte whenSpringBootPropertyProvided_thenProperlyInjected () {assertThat (foo) .isEqualTo ("bar"); }}

4.5. Hiërarchische eigenschappen

Als we eigendommen hebben die gegroepeerd zijn, kunnen we gebruik maken van de @ConfigurationProperties annotatie, waarmee deze eigenschapshiërarchieën worden toegewezen aan grafieken van Java-objecten.

Laten we enkele eigenschappen nemen die worden gebruikt om een ​​databaseverbinding te configureren:

database.url = jdbc: postgresql: / localhost: 5432 / instance database.username = foo database.password = bar

En laten we vervolgens de annotatie gebruiken om ze toe te wijzen aan een databaseobject:

@ConfigurationProperties (prefix = "database") openbare klasse Database {String url; String gebruikersnaam; String wachtwoord; // standaard getters en setters}

Spring Boot past zijn conventie opnieuw toe op de configuratiebenadering, waarbij automatisch wordt toegewezen aan namen van eigenschappen en hun overeenkomstige velden. Het enige dat we hoeven op te geven, is het eigendomsvoorvoegsel.

Als u dieper in de configuratie-eigenschappen wilt graven, bekijk dan ons uitgebreide artikel.

4.6. Alternatief: YAML-bestanden

Spring ondersteunt ook YAML-bestanden.

Dezelfde naamgevingsregels zijn van toepassing op testspecifieke, omgevingsspecifieke en standaardeigenschappenbestanden. Het enige verschil is de bestandsextensie en de afhankelijkheid van de SnakeYAML-bibliotheek die zich op ons klassenpad bevindt.

YAML is vooral goed voor het opslaan van hiërarchische eigenschappen; het volgende eigenschappenbestand:

database.url = jdbc: postgresql: / localhost: 5432 / instance database.username = foo database.password = balkgeheim: foo

is synoniem met het volgende YAML-bestand:

database: url: jdbc: postgresql: / localhost: 5432 / instance gebruikersnaam: foo wachtwoord: bar secret: foo

Het is ook vermeldenswaard dat YAML-bestanden de @PropertySource annotatie, dus als we deze annotatie moeten gebruiken, zou dit ons beperken tot het gebruik van een eigenschappenbestand.

Een ander opmerkelijk punt is dat Spring Boot in versie 2.4.0 de manier heeft veranderd waarop eigenschappen worden geladen vanuit YAML-bestanden met meerdere documenten. Voorheen was de volgorde waarin ze werden toegevoegd, gebaseerd op de volgorde van profielactivering. Met de nieuwe versie volgt het framework echter dezelfde ordeningsregels die we eerder hebben aangegeven .eigendommen bestanden; eigenschappen die lager in het bestand zijn gedeclareerd, overschrijven eenvoudig de hogere eigenschappen.

Bovendien kunnen in deze versie profielen niet meer worden geactiveerd vanuit profielspecifieke documenten, waardoor de uitkomst duidelijker en voorspelbaarder wordt.

4.7. Extra configuratiebestanden importeren

Vóór versie 2.4.0 was Spring Boot toegestaan ​​om aanvullende configuratiebestanden op te nemen met behulp van de spring.config.location en spring.config.additional-location eigenschappen, maar ze hadden bepaalde beperkingen. Ze moesten bijvoorbeeld worden gedefinieerd voordat de toepassing werd gestart (als omgeving of systeemeigenschappen, of met behulp van opdrachtregelargumenten) omdat ze al vroeg in het proces werden gebruikt.

In de genoemde versie, we kunnen de spring.config.import eigenschap binnen de application.properties of application.yml bestand om eenvoudig extra bestanden op te nemen. Deze eigenschap ondersteunt enkele interessante functies:

  • het toevoegen van meerdere bestanden of mappen
  • de bestanden kunnen worden geladen vanuit het klassenpad of vanuit een externe map
  • aangeeft of het opstartproces zou moeten mislukken als een bestand niet wordt gevonden, of dat het een optioneel bestand is
  • extensieloze bestanden importeren

Laten we een geldig voorbeeld bekijken:

spring.config.import = classpath: additional-application.properties, classpath: additionele applicatie [.yml], optioneel: bestand: ./ external.properties, classpath: additionele applicatie-eigenschappen /

Opmerking: hier hebben we deze eigenschap voor de duidelijkheid opgemaakt met behulp van regeleinden.

Spring behandelt invoer als een nieuw document dat direct onder de invoeraangifte wordt ingevoegd.

4.8. Eigenschappen van opdrachtregelargumenten

Naast het gebruik van bestanden, kunnen we eigenschappen rechtstreeks op de opdrachtregel doorgeven:

java -jar app.jar --property = "waarde"

We kunnen dit ook doen via systeemeigenschappen, die vóór het -pot commando in plaats van erachter:

java -Dproperty.name = "waarde" -jar app.jar

4.9. Eigenschappen van omgevingsvariabelen

Spring Boot detecteert ook omgevingsvariabelen en behandelt ze als eigenschappen:

export naam = waarde java -jar app.jar 

4.10. Randomisatie van eigendomswaarden

Als we geen deterministische eigenschapswaarden willen, kunnen we gebruiken RandomValuePropertySource om de waarden van eigenschappen willekeurig te maken:

random.number = $ {random.int} random.long = $ {random.long} random.uuid = $ {random.uuid}

4.11. Extra soorten eigendomsbronnen

Spring Boot ondersteunt een groot aantal eigendomsbronnen en implementeert een goed doordachte ordening om verstandig overschrijven mogelijk te maken. Het loont de moeite om de officiële documentatie te raadplegen, die verder gaat dan het bestek van dit artikel.

5. Configuratie met behulp van rauwe bonen - de PropertySourcesPlaceholderConfigurer

Naast de handige methoden om eigenschappen in Spring te krijgen, kunnen we de eigenschappenconfiguratieboon ook handmatig definiëren en registreren.

Werken met de PropertySourcesPlaceholderConfigurer geeft ons volledige controle over de configuratie, met als nadeel dat het meer uitgebreid en meestal niet nodig is.

Laten we eens kijken hoe we deze bean kunnen definiëren met behulp van Java-configuratie:

@Bean openbare statische PropertySourcesPlaceholderConfigurer properties () {PropertySourcesPlaceholderConfigurer pspc = nieuwe PropertySourcesPlaceholderConfigurer (); Bron [] resources = nieuwe ClassPathResource [] {nieuwe ClassPathResource ("foo.properties")}; pspc.setLocations (bronnen); pspc.setIgnoreUnresolvablePlaceholders (true); retourneer pspc; }

6. Eigenschappen in ouder-kindcontexten

Deze vraag komt keer op keer op: wat gebeurt er als onze webapplicatie heeft een bovenliggende en een onderliggende context? De bovenliggende context kan een aantal gemeenschappelijke kernfunctionaliteit en bonen hebben, en vervolgens een (of meerdere) kindcontexten, die misschien servlet-specifieke bonen bevatten.

Wat is in dat geval de beste manier om eigenschappenbestanden te definiëren en in deze contexten op te nemen? En hoe haalt u deze eigendommen het beste uit de lente?

We zullen een eenvoudige uitsplitsing geven.

Als het bestand gedefinieerd in de oudercontext:

  • @Waarde werkt in Kindcontext: JA
  • @Waarde werkt in Bovenliggende context: JA
  • environment.getProperty in Kindcontext: JA
  • environment.getProperty in Bovenliggende context: JA

Als het bestand gedefinieerd in de onderliggende context:

  • @Waarde werkt in Kindcontext: JA
  • @Waarde werkt in Bovenliggende context: NEE
  • environment.getProperty in Kindcontext: JA
  • environment.getProperty in Bovenliggende context: NEE

7. Conclusie

Dit artikel toonde verschillende voorbeelden van het werken met eigenschappen- en eigenschappenbestanden in Spring.

Zoals altijd is de volledige code die het artikel ondersteunt, beschikbaar op GitHub.