در طول توسعه برنامه های بزرگ این نیاز وجود دارد که بتوانیم بخش هایی از برنامه را برای هدفی اجرا کنیم و مابقی برنامه قابل اجرا نباشند مثلا جهت تست یا زمان توسعه یا زمان ساخت محصول نهایی.
بسته به موقعیت توسعه محصول و نیاز به تست بخش های مختلف میتوان Profile هایی را در Spring داشته باشیم که هر بار بتوانیم روی بخش های مختلف مدیریت داشته باشیم و فعال و غیر فعال نماییم
برای تعریف Profile ها از Profile@ استفاده میکنیم و هر Profile میتواند یک یا چندین اسم بگیرد
استفاده از Profile@ روی Bean :
@Component @Profile("dev") public class DevDatasourceConfig
همچنین نام پروفایل ها میتوانند بصورت NOT هم استفاده شوند :
@Component @Profile("!dev") public class DevDatasourceConfig
در این حالت هنگامی که dev فعال نبود این bean قابل دسترس و اجراست
تعریف آن در فایل تنظیمات XML ای :
<beans profile="dev"> <bean id="devDatasourceConfig" class="org.baeldung.profiles.DevDatasourceConfig" /> </beans>
طریقه ثبت و ست کردن Profile جاری در Container بر چند نوع است:
روش اول از طریق کد برنامه نویسی و با استفاده از WebApplicationInitializer interface :
در web application ها توسط WebApplicationInitializer interface میتوانیم تنظیمات ServletContext را بصورت کدنویسی شده بکار ببریم که یکی از این تنظیمات مربوط به ست کردن Profile جاری است :
@Configuration public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { servletContext.setInitParameter( "spring.profiles.active", "dev"); } }
روش دوم از طریق کد نویس با استفاده از ConfigurableEnvironment :
@Autowired private ConfigurableEnvironment env; ... env.setActiveProfiles("someProfile");
روش سوم از طریق تنظیمات درون web.xml مربوط به تنظیمات Context :
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/app-config.xml</param-value> </context-param> <context-param> <param-name>spring.profiles.active</param-name> <param-value>dev</param-value> </context-param>
روش چهارم از طریق پارامتر های JVM :
-Dspring.profiles.active=dev
روش پنجم از طریق متغییر های محیطی (سیستم عامل):
export spring_profiles_active=dev
روش ششم از طریق تنظیمات Maven پروژه :
در هر بخش پروفایل maven ای میتوانیم تنظیمات مربوط به profile اسپرینگ را هم وارد کنیم
<profiles> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <spring.profiles.active>dev</spring.profiles.active> </properties> </profile> <profile> <id>prod</id> <properties> <spring.profiles.active>prod</spring.profiles.active> </properties> </profile> </profiles>
با تنظیمات بالا مقدار @spring.profiles.active@ در application.properties تغییر خواهد کرد :
spring.profiles.active=@spring.profiles.active@
برای فعال کردن تنظیمات بالا در maven نیاز داریم که در فایل pom.xml پروژه filtering را فعال کنیم:
<build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> ... </build>
حالا میتوانیم با سویچ P- مطابق profile تعیین شده پروژه را package کنیم :
mvn clean package -Pprod
عبارت prod میتواند مقادیر دیگری مثل test , dev را هم بگیرد. این سویچ با مقدار prod همچنین مقدار spring.profiles.active را به prod تغییر خواهد داد
ApplicationContext@ برای تست : در زمان تست بسیار کاربردی است که بتوانیم حالت تست را از از وضعیتی به وضعیت دیگر تغییر دهیم برای این منظور میتوانیم از این annotation استفاده کنیم در حقیقت به ApplicationContext میگوییم که کدام profile را باید در نظر بگیرد
@ActiveProfiles("dev")
پروفایل default : هر bean ای که هیچ Profile@ ای برای آن تعیین نشده است پروفایل آن مقدار default را دارد لذا میتوانیم برای اجرا یا تست و ... از مقدار default برای این نوع از profile ها استفاده کنیم "spring.profiles.default"
برای فهمیدن و بدست آوردن profile ست شده ی جاری و لیست پروفایل های کل، میتوانیم از دو راه زیر استفاده کنیم :
روش اول از طریق Environment Bean :
public class ProfileManager { @Autowired private Environment environment; public void getActiveProfiles() { for (String profileName : environment.getActiveProfiles()) { System.out.println("Currently active profile - " + profileName); } } }
روش دوم از طریق تزریق مقدار spring.profiles.active property :
@Value("${spring.profiles.active}") private String activeProfile;
در این روش متغییر activeProfile که از نوع String است میتواند مقدار profile جاری را به ما بدهد و در صورت وجود چندین پروفایل اسامی آنها با کاما از هم جدا میباشد
در کد بالا در صورتی که هیچ پروفایلی موجود نبود خطای IllegalArgumentException را خواهیم گرفت و برای جلوگیری از این خطا میتوانیم مقدار default را به این صورت تعریف کنیم:
@Value("${spring.profiles.active:}") private String activeProfile;
با کد بالا که میتوانیم وجود یک ':' اضافی را مشاهده کنیم در صورت نبود profile مقدار خالی را خواهیم داشت حال اگر پروفایل ها چند تا بودن میتوانیم با split کردن رشته آنها را از هم تفکیک کنیم :
public class ProfileManager { @Value("${spring.profiles.active:}") private String activeProfiles; public String getActiveProfiles() { for (String profileName : activeProfiles.split(",")) { System.out.println("Currently active profile - " + profileName); } } }
مثال هایی از استفاده از profile@ در کد :
بیاییم در نظر بگیریم که کدی داریم که منابع دیتای آن برای دو حالت development و production باید قابل استفاده باشد
ابتدا یک اینترفیس برای تنظیمات ایجاد میکنیم :
public interface DatasourceConfig { public void setup(); }
حالا دو Bean را برای حالت development و production پیاده سازی میکنیم :
@Component @Profile("dev") public class DevDatasourceConfig implements DatasourceConfig { @Override public void setup() { System.out.println("Setting up datasource for DEV environment. "); } }
@Component @Profile("production") public class ProductionDatasourceConfig implements DatasourceConfig { @Override public void setup() { System.out.println("Setting up datasource for PRODUCTION environment. "); } }
حالا میتوانیم کدمان را تست کنیم :
public class SpringProfilesWithMavenPropertiesIntegrationTest { @Autowired DatasourceConfig datasourceConfig; public void setupDatasource() { datasourceConfig.setup(); } }
وقتی پروفایل dev را فعال کنیم میتوانیم خروجی زیر را مشاهده کنیم :
Setting up datasource for DEV environment.
پروفایل ها در Spring Boot :
در Spring Boot از تمامی ویژگی های profile که تاکنون شرح داده شد پشتیبانی میشود و یک سری ویژگی های بیشتری را هم ارائه میدهد
در Spring Boot میتوانیم برای فعال کردن profile جاری، به عنوان یک property آنرا فعال کنیم و Spring Boot آنرا بصورت اتوماتیک ست خواهد کرد :
spring.profiles.active=dev
و در روش کدنویسی میتوان در کلاس SpringApplication آنرا ست کنیم :
SpringApplication.setAdditionalProfiles("dev");
<plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <profiles> <profile>dev</profile> </profiles> </configuration> </plugin> ... </plugins>
سپس توسط فرمان زیر آنرا اجرا کنیم :
mvn spring-boot:run
مهمترین ویژگی ای که Spring Boot برای profile مهیا میکند کانفیگ کردن آن از طریق فایل application-[profile].properties مختلف است.
Spring Boot وقتی فایل application.properties را load میکند سپس به دنبال الگوی application-[profile].properties میگردد که تنظیمات مربوط به هر پروفایل را دارا است برای مثال میتوانیم این دو فایل property را داشته باشیم :
application-dev.properties application-production.properties
که در application-production.properties تنظیمات زیر را استفاده کردیم
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/db spring.datasource.username=root spring.datasource.password=root
و در حالت development و در فایل application-dev.properties تنظیمات مربوطه را استفاده میکنیم :
spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 spring.datasource.username=sa spring.datasource.password=sa