# თავი 5: Configuration და Profiles --- ## 5.1 Hardcoded მნიშვნელობებიდან Configurable სისტემამდე წინა თავებში ჩვენ შევქმენით controller-ები, template-ები, entity-ები და repository-ები — თუმცა ყოველ ჯერზე, როდესაც მნიშვნელობის შეცვლა გვჭირდებოდა, Java კოდის რედაქტირება გვიწევდა. მონაცემთა ბაზის URL მითითებული იყო `application.properties` ფაილში მხოლოდ იმიტომ, რომ Spring Boot-მა ასე მიგვითითა, მაგრამ ჩვენ არ დავფიქრებულვართ configuration-ზე, როგორც ცალკეულ კონცეფციაზე. რა ხდება მაშინ, როდესაც აპლიკაციის გაშვება გჭირდებათ სატესტო სერვერზე სხვა მონაცემთა ბაზით? ან გსურთ timeout-ის მნიშვნელობის შეცვლა კოდის ხელახალი კომპილაციის (recompiling) გარეშე? როგორ უნდა დავმალოთ production-ის პაროლები source code-დან? ეს თავი გაგაცნობთ Spring Boot-ის **externalized configuration** სისტემას — მექანიზმებს, რომლებიც საშუალებას გაძლევთ გამიჯნოთ კონფიგურაცია კოდისგან. ამით ერთი და იგივე კომპილირებული აპლიკაცია სხვადასხვა გარემოში (environment) განსხვავებულად იქცევა. ჩვენ ვისწავლით, როგორ პოულობს და ანიჭებს პრიორიტეტს Spring Boot კონფიგურაციის მნიშვნელობებს, როგორ გამოვიყენოთ `@Value` მარტივი ინექციისთვის, როგორ დავაკავშიროთ სტრუქტურირებული მონაცემები type-safe Java ობიექტებთან `@ConfigurationProperties`-ის მეშვეობით და როგორ გამოვიყენოთ **Spring profiles** სხვადასხვა გარემოსთვის (development, testing, production). თავის ბოლოს თქვენ შეძლებთ აპლიკაციის გადართვას H2-დან PostgreSQL-ზე მხოლოდ ერთი profile-ის შეცვლით — Java კოდთან შეხების გარეშე. --- ## 5.2 Externalized Configuration Externalized configuration-ის იდეა მარტივია: მნიშვნელობები, რომლებიც შეიძლება შეიცვალოს სხვადასხვა გარემოში, არ უნდა იყოს ჩაშენებული (baked) თქვენს კოდში. ამის ნაცვლად, ისინი ინახება გარე წყაროებში, რომლებსაც Spring Boot კითხულობს გაშვებისას (startup). Spring Boot მხარს უჭერს კონფიგურაციის რამდენიმე ტიპს: `application.properties` და `application.yml` ფაილებს, ოპერაციული სისტემის environment variables-ს, Java system properties-ს და command-line arguments-ს. ყველა ეს წყარო ერთიანდება ერთიან `Environment` აბსტრაქციაში. თქვენი კოდი ითხოვს მნიშვნელობას `Environment`-დან, ხოლო Spring Boot თავად ადგენს, თუ საიდან მიიღოს იგი. კონფიგურაციის მნიშვნელობების გამოყენება შესაძლებელია სამი გზით: პირდაპირი ინექცია bean-ის ველებში `@Value` ანოტაციით, პროგრამული წვდომა `Environment` ობიექტის მეშვეობით, ან სტრუქტურირებული დაკავშირება Java ობიექტებთან `@ConfigurationProperties`-ით. --- ## 5.3 კონფიგურაციის ფაილების ფორმატები Spring Boot მხარს უჭერს ორ ფორმატს: **properties** და **YAML**. ორივე მათგანი თავსდება `src/main/resources/` დირექტორიაში. ### application.properties Properties ფორმატი იყენებს მარტივ key-value წყვილებს: ```properties app.title=My Spring Boot App app.max-connections=120 app.servers=dev,qa,prod server.port=8080 ``` ### application.yml YAML ფორმატი იყენებს ინდენტაციას (indentation) იერარქიის გამოსახატად: ```yaml app: title: My Spring Boot App max-connections: 120 servers: - dev - qa - prod server: port: 8080 ``` ორივე ფორმატი ურთიერთჩანაცვლებადია. YAML უფრო მოსახერხებელია იერარქიული სტრუქტურებისთვის, რადგან თავიდან გვაცილებს პრეფიქსების გამეორებას. --- ## 5.4 კონფიგურაციის მნიშვნელობების რეზოლუცია როდესაც ერთი და იგივე პარამეტრი განსაზღვრულია რამდენიმე წყაროში, Spring Boot იყენებს პრიორიტეტების მკაცრად განსაზღვრულ რიგითობას (დაბალიდან მაღლისკენ): 1. Default მნიშვნელობები (განსაზღვრული კოდში: `@Value("${key:default}")`) 2. `application.properties` ან `application.yml` classpath-ში 3. Profile-სპეციფიკური ფაილები (`application-dev.properties` და ა.შ.) 4. OS environment variables 5. Java system properties (`-Dkey=value`) 6. Command-line arguments (`--key=value`) მაღალი პრიორიტეტის წყარო ყოველთვის აუქმებს (overrides) დაბალს. ეს ნიშნავს, რომ command-line argument ყოველთვის სჯობნის properties ფაილს. --- ## 5.5 Property-ის ინექცია @Value ანოტაციით მნიშვნელობის წაკითხვის ყველაზე პირდაპირი გზაა `@Value` ანოტაცია. Spring ახდენს ტიპების ავტომატურ კონვერტაციას (მაგალითად, String-ის გადაყვანას `int`-ში ან `List`-ში). ```java @Service public class AppInfoService { @Value("${app.title}") private String title; @Value("${app.max-connections}") private int maxConnections; @Value("${app.servers}") private List servers; @Value("${feature.enabled:true}") private boolean featureEnabled; } ``` `${feature.enabled:true}` სინტაქსი უზრუნველყოფს default მნიშვნელობას, თუ პარამეტრი არ მოიძებნა. ### @Value-ს შეზღუდვები მიუხედავად სიმარტივისა, `@Value`-ს აქვს ნაკლოვანებები: * **გაფანტული კონფიგურაცია:** ერთი და იგივე property-ის სახელი შეიძლება ბევრგან იყოს გამოყენებული, რაც ართულებს რედაქტირებას. * **Type safety-ს ნაკლებობა:** ბინდინგის დროს ვალიდაცია არ ხდება. * **IDE მხარდაჭერის არქონა:** რთულია property-ების ძებნა და autocomplete-ის გამოყენება. --- ## 5.6 სტრუქტურირებული კონფიგურაცია @ConfigurationProperties-ით `@ConfigurationProperties` საშუალებას გაძლევთ მთელი სექცია დაუკავშიროთ კონკრეტულ Java კლასს, რაც უზრუნველყოფს **type-safety**-ს. ### Configuration Properties კლასის განსაზღვრა ```java @Component @ConfigurationProperties(prefix = "my.app") public class MyAppProperties { private String name; private int timeout; private List servers; // getters and setters } ``` `prefix = "my.app"` მიუთითებს Spring-ს, რომ მოძებნოს ყველა property, რომელიც იწყება ამ პრეფიქსით. ### ვალიდაცია თქვენ შეგიძლიათ გამოიყენოთ Bean Validation ანოტაციები (მაგ. `@NotBlank`, `@Min`) პირდაპირ configuration კლასზე: ```java @Validated @Component @ConfigurationProperties(prefix = "my.app") public class MyAppProperties { @NotBlank private String name; @Min(1) private int timeout; private List servers; // ... } ``` --- ## 5.8 Spring Profiles რეალური აპლიკაციები მუშაობენ სხვადასხვა გარემოში: დეველოპერის ლეპტოპი, CI სერვერი, staging და production. **Spring profiles** საშუალებას გაძლევთ დააჯგუფოთ კონფიგურაციები და გააქტიუროთ მხოლოდ საჭირო ჯგუფი. ### Profile-ის გააქტიურება Profile-ის გააქტიურების რამდენიმე გზა არსებობს: * **application.properties-ში:** `spring.profiles.active=dev` * **Command-line-დან:** `java -jar myapp.jar --spring.profiles.active=prod` * **Environment variable-ით:** `export SPRING_PROFILES_ACTIVE=prod` --- ## 5.9 Profile-სპეციფიკური ფაილები Spring Boot იყენებს დასახელების კონვენციას: `application-{profile}.properties`. მაგალითად: * `application.properties` — ზოგადი პარამეტრები. * `application-dev.properties` — იტვირთება მხოლოდ "dev" profile-ის დროს. * `application-prod.properties` — იტვირთება მხოლოდ "prod" profile-ის დროს. --- ## 5.10 Bean-ების პირობითი რეგისტრაცია @Profile-ით ზოგჯერ საჭიროა მთლიანი კომპონენტების (Bean) ჩანაცვლება გარემოს მიხედვით. `@Profile` ანოტაცია სწორედ ამისთვისაა: ```java @Configuration public class DataSourceConfig { @Bean @Profile("dev") public DataSource h2DataSource() { return new HikariDataSource(new HikariConfig("/h2.properties")); } @Bean @Profile("prod") public DataSource postgresDataSource() { return new HikariDataSource(new HikariConfig("/postgres.properties")); } } ``` --- ## 5.12 Environment Variables და საიდუმლო ინფორმაცია უსაფრთხოების მიზნით, სენსიტიური მონაცემები (პაროლები, API keys) არასოდეს არ უნდა შეინახოთ source control-ში. ამისთვის გამოიყენება **Environment Variables** და placeholder-ები: ```yaml spring: datasource: username: ${DB_USERNAME} password: ${DB_PASSWORD} ``` --- ## 5.14 საუკეთესო პრაქტიკა (Best Practices) 1. **შეინარჩუნეთ სიმარტივე:** გამოიყენეთ 2-3 ძირითადი profile (`dev`, `test`, `prod`). 2. **არავითარი პაროლები კოდში:** გამოიყენეთ environment variables საიდუმლო ინფორმაციისთვის. 3. **Default Profile:** ყოველთვის მიუთითეთ default profile `application.properties`-ში. 4. **ამჯობინეთ @ConfigurationProperties:** `@Value` გამოიყენეთ მხოლოდ იზოლირებულ, მარტივ შემთხვევებში. 5. **ვალიდაცია:** გამოიყენეთ `@Validated`, რათა შეცდომები აპლიკაციის გაშვებისთანავე აღმოაჩინოთ. --- ## შეჯამება ამ თავში ჩვენ განვიხილეთ Spring Boot-ის externalized configuration სისტემა. ვისწავლეთ სხვადასხვა წყაროდან მონაცემების მიღება, `@Value` და `@ConfigurationProperties` ანოტაციების გამოყენება და Spring Profiles-ის მეშვეობით აპლიკაციის სხვადასხვა გარემოზე მორგება Java კოდის შეუცვლელად.