Browse Source
Allows a convenient mechanism for contributing a PropertySource to the enclosing Spring Environment. See @PropertySource Javadoc for complete details and PropertySourceAnnotationTests for examples. Issue: SPR-8314 git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4289 50f2f4bb-b051-0410-bef5-90022cba6387pull/1/merge
6 changed files with 296 additions and 0 deletions
@ -0,0 +1,125 @@
@@ -0,0 +1,125 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.context.annotation; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* Annotation providing a convenient and declarative mechanism for adding a |
||||
* {@link org.springframework.core.env.PropertySource PropertySource} to Spring's |
||||
* {@link org.springframework.core.env.Environment Environment}. To be used in |
||||
* conjunction with @{@link Configuration} classes. |
||||
* |
||||
* <h3>Example usage</h3> |
||||
* <p>Given a file {@code app.properties} containing the key/value pair |
||||
* {@code testbean.name=myTestBean}, the following {@code @Configuration} class
|
||||
* uses {@code @PropertySource} to contribute {@code app.properties} to the |
||||
* {@code Environment}'s set of {@code PropertySources}. |
||||
* |
||||
* <pre> |
||||
* @Configuration |
||||
* @PropertySource("classpath:/com/myco/app.properties") |
||||
* public class AppConfig { |
||||
* @Autowired |
||||
* Environment env; |
||||
* |
||||
* @Bean |
||||
* public TestBean testBean() { |
||||
* TestBean testBean = new TestBean(); |
||||
* testBean.setName(env.getProperty("testbean.name")); |
||||
* return testBean; |
||||
* } |
||||
* }</pre> |
||||
* |
||||
* Notice that the {@code Environment} object is @{@link Autowired} into the |
||||
* configuration class and then used when populating the {@code TestBean} |
||||
* object. Given the configuration above, a call to {@code testBean.getName()} will |
||||
* return "myTestBean". |
||||
* |
||||
* <h3>A note on property overriding with @PropertySource</h3> |
||||
* In cases where a given property key exists in more than one {@code .properties} |
||||
* file, the last {@code @PropertySource} annotation processed will 'win' and override. |
||||
* |
||||
* For example, given two properties files {@code a.properties} and |
||||
* {@code b.properties}, consider the following two configuration classes |
||||
* that reference them with {@code @PropertySource} annotations: |
||||
* |
||||
* <pre> |
||||
* @Configuration |
||||
* @PropertySource("classpath:/com/myco/a.properties") |
||||
* public class ConfigA { } |
||||
* |
||||
* @Configuration |
||||
* @PropertySource("classpath:/com/myco/b.properties") |
||||
* public class ConfigB { } |
||||
* </pre> |
||||
* |
||||
* The override ordering depends on the order in which these classes are registered |
||||
* with the application context. |
||||
* <pre> |
||||
* AnnotationConfigApplicationContext ctx = |
||||
* new AnnotationConfigApplicationContext(); |
||||
* ctx.register(ConfigA.class); |
||||
* ctx.register(ConfigB.class); |
||||
* ctx.refresh(); |
||||
* </pre> |
||||
* |
||||
* In the scenario above, the properties in {@code b.properties} will override any |
||||
* duplicates that exist in {@code a.properties}, because {@code ConfigB} was registered |
||||
* last. |
||||
* |
||||
* <p>In certain situations, it may not be possible or practical to tightly control |
||||
* property source ordering when using {@code @ProperySource} annotations. For example, |
||||
* if the {@code @Configuration} classes above were registered via component-scanning, |
||||
* the ordering is difficult to predict. In such cases - and if overriding is important - |
||||
* it is recommended that the user fall back to using the programmatic PropertySource API. |
||||
* See {@link org.springframework.core.env.ConfigurableEnvironment ConfigurableEnvironment} and |
||||
* {@link org.springframework.core.env.MutablePropertySources MutablePropertySources} Javadoc |
||||
* for details. |
||||
|
||||
* |
||||
* @author Chris Beams |
||||
* @since 3.1 |
||||
*/ |
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
public @interface PropertySource { |
||||
|
||||
/** |
||||
* Indicate the name of this PropertySource. If omitted, a name |
||||
* will be generated based on the description of the underlying |
||||
* resource. |
||||
* @see org.springframework.core.env.PropertySource#getName() |
||||
* @see org.springframework.core.io.Resource#getDescription() |
||||
*/ |
||||
String name() default ""; |
||||
|
||||
/** |
||||
* Indicate the resource location of the properties file to be loaded. |
||||
* For example, {@code "classpath:/com/myco/app.properties"} or |
||||
* {@code "file:/path/to/file"}. Note that resource location wildcards |
||||
* are not permitted, and that a location must evaluate to exactly one |
||||
* {@code .properties} resource. |
||||
*/ |
||||
String value(); |
||||
|
||||
} |
||||
@ -0,0 +1,125 @@
@@ -0,0 +1,125 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.context.annotation; |
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo; |
||||
import static org.hamcrest.CoreMatchers.is; |
||||
import static org.junit.Assert.assertThat; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
import javax.inject.Inject; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.core.env.Environment; |
||||
import org.springframework.core.env.MutablePropertySources; |
||||
|
||||
import test.beans.TestBean; |
||||
|
||||
/** |
||||
* Tests the processing of @PropertySource annotations on @Configuration classes. |
||||
* |
||||
* @author Chris Beams |
||||
* @since 3.1 |
||||
*/ |
||||
public class PropertySourceAnnotationTests { |
||||
|
||||
@Test |
||||
public void withExplicitName() { |
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); |
||||
ctx.register(ConfigWithExplicitName.class); |
||||
ctx.refresh(); |
||||
assertTrue("property source p1 was not added", |
||||
ctx.getEnvironment().getPropertySources().contains("p1")); |
||||
assertThat(ctx.getBean(TestBean.class).getName(), equalTo("p1TestBean")); |
||||
|
||||
// assert that the property source was added last to the set of sources
|
||||
String name; |
||||
MutablePropertySources sources = ctx.getEnvironment().getPropertySources(); |
||||
Iterator<org.springframework.core.env.PropertySource<?>> iterator = sources.iterator(); |
||||
do { |
||||
name = iterator.next().getName(); |
||||
} |
||||
while(iterator.hasNext()); |
||||
|
||||
assertThat(name, is("p1")); |
||||
} |
||||
|
||||
@Test |
||||
public void withImplicitName() { |
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); |
||||
ctx.register(ConfigWithImplicitName.class); |
||||
ctx.refresh(); |
||||
assertTrue("property source p1 was not added", |
||||
ctx.getEnvironment().getPropertySources().contains("class path resource [org/springframework/context/annotation/p1.properties]")); |
||||
assertThat(ctx.getBean(TestBean.class).getName(), equalTo("p1TestBean")); |
||||
} |
||||
|
||||
/** |
||||
* Tests the LIFO behavior of @PropertySource annotaitons. |
||||
* The last one registered should 'win'. |
||||
*/ |
||||
@Test |
||||
public void orderingIsLifo() { |
||||
{ |
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); |
||||
ctx.register(ConfigWithImplicitName.class, P2Config.class); |
||||
ctx.refresh(); |
||||
// p2 should 'win' as it was registered last
|
||||
assertThat(ctx.getBean(TestBean.class).getName(), equalTo("p2TestBean")); |
||||
} |
||||
|
||||
{ |
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); |
||||
ctx.register(P2Config.class, ConfigWithImplicitName.class); |
||||
ctx.refresh(); |
||||
// p1 should 'win' as it was registered last
|
||||
assertThat(ctx.getBean(TestBean.class).getName(), equalTo("p1TestBean")); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Configuration |
||||
@PropertySource(name="p1", value="classpath:org/springframework/context/annotation/p1.properties") |
||||
static class ConfigWithExplicitName { |
||||
@Inject Environment env; |
||||
|
||||
@Bean |
||||
public TestBean testBean() { |
||||
return new TestBean(env.getProperty("testbean.name")); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Configuration |
||||
@PropertySource("classpath:org/springframework/context/annotation/p1.properties") |
||||
static class ConfigWithImplicitName { |
||||
@Inject Environment env; |
||||
|
||||
@Bean |
||||
public TestBean testBean() { |
||||
return new TestBean(env.getProperty("testbean.name")); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Configuration |
||||
@PropertySource("classpath:org/springframework/context/annotation/p2.properties") |
||||
static class P2Config { |
||||
} |
||||
} |
||||
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
testbean.name=p1TestBean |
||||
Loading…
Reference in new issue