در این بخش به بحث چگونگی استفاده از Property ها در Spring و نحوه کانفیگ کردن آنها با PropertySource@ و روش XML ای آن و نحوه کارکرد آن در Spring Boot میپردازیم.
نحوه ثبت یک Property فایل توسط Annotation : در یک کلاس Configuration@ میتوان از PropertySource@ استفاده کنیم و آدرس فایل property را به عنوان آرگومان ارسال کنیم :
@Configuration
@PropertySource("classpath:foo.properties")
public class PropertiesWithJavaConfig {
//...
}
میتوانیم با استفاده از placeholder بصورت داینامیک آدرس property file را بدهیم اینطوری نیازی نیست که آدرس property فایل ثابت باشد :
@PropertySource({
"classpath:persistence-${envTarget:mysql}.properties"
})
...
برای معرفی چندین property فایل به این صورت میتوان اقدام کرد :
//java 8 feature
@PropertySource("classpath:foo.properties")
@PropertySource("classpath:bar.properties")
public class PropertiesWithJavaConfig {
//...
}
@PropertySources({
@PropertySource("classpath:foo.properties"),
@PropertySource("classpath:bar.properties")
})
public class PropertiesWithJavaConfig {
//...
}
در این حالت اگر یک مقداری در فایل های property دوبار استفاده شود آخرین آنها در نظر گرفته میشود و الویت بالاتری دارد
طریقه تعریف توسط xml :
<context:property-placeholder location="classpath:foo.properties" />
در این حالت فایل foo.properties باید در مسیر /src/main/resources موجود باشد
حالت تعریف چند تایی در xml :
<context:property-placeholder location="classpath:foo.properties, classpath:bar.properties"/>
خواندن و استفاده کردن از مقادیر Property ها :
روش اول با استفاده از Value@ میتوانیم مقادیر موجود در property ها را خوانده و در متغییری تزریق کنیم
@Value( "${jdbc.url}" )
private String jdbcUrl;
خواندن مقادیر و در صورت عدم وجود آن، با یک مقدار پیش فرض پر میشود :
@Value( "${jdbc.url:aDefaultUrl}" )
private String jdbcUrl;
خواندن مقادیر در xml فایل ها :
<bean id="dataSource">
<property name="url" value="${jdbc.url}" />
</bean>
روش دوم با استفاده از Environment API در Spring :
@Autowired
private Environment env;
...
dataSource.setUrl(env.getProperty("jdbc.url"));
استفاده از property در Spring Boot :
Spring Boot در ابتدای اجرا دنبال یک فایل بصورت پیش فرض بنام application.properties در مسیر src/main/resources میگردد و بصورت اتوماتیک آنرا شناسایی و استفاده میکند و ما نیز میتوانیم تنظیمات خود را در داخل این فایل قرار دهیم و دیگر نیازی نداریم که فایل property خودمان را به Spring معرفی کنیم
همینطور میتوانیم فایل property تنظیمات را در خط فرمان موقع اجرا کد به عنوان آرگومان ارسال کنیم :
java -jar app.jar --spring.config.location=classpath:/another-location.properties
همچنین ما میتوانیم برای هر profile موجود یک فایل property مجزا در مسیر src/main/resources داشته باشیم که نیاز دارد الگوی زیر را داشته باشد. در صورت وجود این تنظیمات جانبی همچنان فایل application.properties به عنوان پیش فرض خوانده میشود
application-[environment].properties
مثل : application-dev.properties
اگر نیاز باشد کد با شرایط تستی تست شود و تنظیمات مختص خود را داشته باشد نیاز است که تنظیمات مربوطه در مسیر src/test/resources گذاشته شود
TestPropertySource@ : اگر در شرایط تست نیاز داریم که ادرس فایل تنظیمات property را بصورت دستی ارسال کنیم میتوانیم با این annotation این کار را بکنیم :
@ContextConfiguration
@TestPropertySource("/my-test.properties")
public class IntegrationTests {
// tests
}
حتی میتوانیم بدون ادرس دهی فایل، مقادیر و نام های property ها را بصورت دستی و hardcode ارسال کنیم :
@ContextConfiguration
@TestPropertySource("foo=bar", "bar=foo")
public class IntegrationTests {
// tests
}
همچنین میتوانیم مقادیر بالا را با کمک SpringBootTest@ وارد کنیم :
@SpringBootTest(properties = {"foo=bar", "bar=foo"})
public class IntegrationTests {
// tests
}
ConfigurationProperties@ : زمانی که property فایل های سلسله مراتبی داشته باشیم میتوانیم از این annotation استفاده کنیم
استفاده از yaml به جای properties فایل ها :
در Spring میتوانیم از فایل و ساختار yaml هم استفاده کنیم و تمامی شرایط آن با properties مشابه است و تنها فرق آن در ساختار آن و ساپورت نکردن PeropertySource@ از آن است حالا نگاهی کنیم به ساختار داخلی yaml :
مدل properties :
database.url=jdbc:postgresql:/localhost:5432/instance database.username=foo database.password=bar secret=foo
مدل yaml :
database: url: jdbc:postgresql:/localhost:5432/instance username: foo password: bar secret: foo
ارسال مقادیر property از طریق خط فرمان :
java -jar app.jar --property="value"
همچنین میتوانید از طریق سویچ سیستمی آنرا انجام دهیم :
java -Dproperty.name="value" -jar app.jar
از طریق متغییر های سیستمی هم میتوان نام و مقادیری را اعمال کنیم :
export name=value java -jar app.jar
تولید مقادیر تصادفی :
random.number=${random.int}
random.long=${random.long}
random.uuid=${random.uuid}
تعریف یک property خام با استفاده از کلاس PropertyPlaceholderConfigurer بصورت دستی:
این روش کاربرد زیادی ندارد ولی شاید شرایطی بوجود آید که نیاز باشد باید یک bean ایجاد کنیم که مقدار برگشتی آن از جنس کلاس PropertySourcesPlaceholderConfigurer باشد و اینطوری مقادیر property بصورت اتوماتیک ثبت خواهند شد :
@Bean
public static PropertySourcesPlaceholderConfigurer properties(){
PropertySourcesPlaceholderConfigurer pspc
= new PropertySourcesPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[ ]
{ new ClassPathResource( "foo.properties" ) };
pspc.setLocations( resources );
pspc.setIgnoreUnresolvablePlaceholders( true );
return pspc;
}
روش تعریف یک property خام بصورت دستی با xml :
این روش هم کاربرد زیادی ندارد
<bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:foo.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
Context to Context - Parent Child :
حالتی پیش میاد که (بیشتر در وب) که برنامه اینقدر بزرگ است که یک Context بزرگ چند Context داخلی در خودش دارد و اینجا مقادیر property چطور در Context پدر و فرزند قابل دسترس است ؟
- حالتی که property ها در فرمت xml و با استفاده از <property-placeholder> تعریف شده باشند :
اگر فایل در پدر تعریف شده باشد دسترسی ها به این نحو است :
@Value works in Child context: NO @Value works in Parent context: YES
اگر فایل در فرزند تعریف شده باشد دسترسی ها به این نحو است :
@Value works in Child context: YES @Value works in Parent context: NO
در مورد Environment API همانطور که قبلا توضیح دادیم چون با استفاده از xml و <property-placeholder> تعریف شده است دسترسی بکل وجود نخواهد داشت:
environment.getProperty works in either context: NO
- حالتی که property ها از طریق PropertySource@ تعریف شده باشند :
اگر فایل در پدر تعریف شده باشد دسترسی ها به این نحو است :
@Value works in Child context: YES @Value works in Parent context: YES environment.getProperty in Child context: YES environment.getProperty in Parent context: YES
اگر فایل در فرزند تعریف شده باشد دسترسی ها به این نحو است :
@Value works in Child context: YES @Value works in Parent context: NO environment.getProperty in Child context: YES environment.getProperty in Parent context: NO