Spring Boot Yapılandırmasını Özelleştirme: Auto-Configuration Override

Spring Boot; otomatik yapılandırma, starter bağımlılıklar ve gömülü sunucu sayesinde hızlı başlangıç sağlar. Ancak her uygulama “tek beden” değildir. Bu rehberde, auto-configuration’u gerektiğinde nasıl devre dışı bırakıp özelleştireceğinizi, dış yapılandırmayla (properties/YAML) ince ayar yapmayı, profillerle ortam ayrımı yapmayı ve özel hata sayfası tasarlamayı öğreneceksiniz.

1) Auto-Configuration Nedir? Ne Zaman Geçersiz Kılınır?

Spring Boot, classpath’te gördüğü kütüphanelere ve mevcut bean’lere bakarak “koşullu” yapılandırma uygular. Bu sayede; web, veri erişimi, şablon motorları, güvenlik ve daha onlarca alan için sıfır çabayla başlangıç yaparsınız. Kolaylık Hız Koşullu Yapılandırma

Ancak bazı durumlarda (özellikle güvenlik, loglama, veritabanı gibi konularda) auto-configuration’un “en iyi tahmini” size uymayabilir. Böyle bir durumda Spring Boot, uygulamanızın kendi yapılandırmasına öncelik verir; yani siz manuel bir bean veya config yazdığınızda otomatik olanını saygıyla geri çeker.

İpucu: Auto-configuration’u geçersiz kılmak için çoğu zaman tek yapmanız gereken, ilgili bean’i veya yapılandırmayı kendiniz tanımlamaktır.

2) Örnek: Spring Security’yi Manuel Olarak Özelleştirmek

spring-boot-starter-security eklendiğinde varsayılan olarak HTTP Basic Authentication gelir; kullanıcı adı user, parola ise her çalıştırmada log’a üretilir. Bu, gerçek projelerde çoğu zaman yeterli değildir. Kendi login sayfanızı ve doğrulama mantığınızı tanımlayın.

2.1. Güvenlik Starter’ı Ekle

implementation "org.springframework.boot:spring-boot-starter-security"

2.2. WebSecurityConfigurerAdapter ile Özelleştir

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private ReaderRepository readerRepository;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
        .antMatchers("/").hasRole("READER")
        .antMatchers("/**").permitAll()
      .and()
        .formLogin()
          .loginPage("/login")
          .failureUrl("/login?error=true");
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(username -> readerRepository.findOne(username));
  }
}

Üstteki yapılandırma, / istekleri için READER rolü ister, diğer tüm istekleri serbest bırakır, özel bir login sayfası kullanır ve kullanıcıları JPA üzerinden doğrular.

2.3. UserDetails Tabanlı Varlık

@Entity
public class Reader implements UserDetails {
  @Id
  private String username;
  private String fullname;
  private String password;

  @Override public Collection<? extends GrantedAuthority> getAuthorities() {
    return Arrays.asList(new SimpleGrantedAuthority("READER"));
  }
  @Override public boolean isAccountNonExpired() { return true; }
  @Override public boolean isAccountNonLocked() { return true; }
  @Override public boolean isCredentialsNonExpired() { return true; }
  @Override public boolean isEnabled() { return true; }

  // getter/setter
}

Bu yaklaşımda Spring Security, doğrudan JPA varlığınızı kullanıcı olarak kullanır. Basit örnek için idealdir.

Dikkat: Gerçek sistemlerde yetkiler ayrı tablo/ilişkilerle yönetilir; hesap kilitleme/son kullanma gibi bayraklar da veri tabanından okunur. Bu örnek öğretici amaçlı sade tutulmuştur.

3) Koşullu Yapılandırma: @ConditionalOnMissingBean ve Arkası

Auto-configuration sınıfları, Spring 4 ile gelen “koşullu yapılandırma” desteğini kullanır. Önemli taşlardan biri @ConditionalOnMissingBean’dir: eğer aynı tipte bir bean zaten uygulama tarafından sağlanmışsa, auto-configuration o bean’i yaratmaz.

@Bean
@ConditionalOnMissingBean(JdbcOperations.class)
public JdbcTemplate jdbcTemplate() {
  return new JdbcTemplate(this.dataSource);
}

Benzer şekilde SpringBootWebSecurityConfiguration, WebSecurityConfiguration tipi bir bean bulunursa devreye girmez. Siz @EnableWebSecurity kullandığınızda bu koşul sağlanır ve kendi güvenlik config’iniz öne geçer.

4) Dış Yapılandırma: application.properties & application.yml

Spring Boot, 300+ özelliği dışarıdan ayarlamanıza izin verir: komut satırı, JNDI, sistem özellikleri, ortam değişkenleri, application.properties ve application.yml. Öncelik sırası en üstte komut satırı olacak şekilde düzenlenmiştir.

Öncelik (yüksek → düşük)
  1. Komut satırı argümanları
  2. JNDI (java:comp/env)
  3. JVM sistem özellikleri
  4. Ortam değişkenleri
  5. application.properties / application.yml (dış → iç)
  6. @PropertySource
  7. Varsayılanlar
Konumlar
  • ./config/ dizini (dış)
  • Uygulamanın çalıştığı kök dizin (dış)
  • classpath:config/ (iç)
  • classpath:/ kök (iç)

Aynı seviyede hem properties hem YAML varsa, YAML değerleri properties’i geçersiz kılar.

5) İnce Ayar Örnekleri

5.1. Thymeleaf Cache’i Kapama (Geliştirme için)

spring.thymeleaf.cache=false

Freemarker, Groovy Templates, Velocity için de benzer spring.*.cache anahtarları mevcuttur.

5.2. Gömülü Sunucu Portu

server.port=8000

Birden fazla uygulamayı aynı makinede çalıştırırken port çakışmalarını önler.

5.3. HTTPS Etkinleştirme

$ keytool -keystore mykeys.jks -genkey -alias tomcat -keyalg RSA
server:
  port: 8443
  ssl:
    key-store: classpath:mykeys.jks
    key-store-password: letmein
    key-password: letmein

Geliştirme sırasında tarayıcı güven uyarısı görebilirsiniz; localhost için normaldir.

5.4. Logging Seviyeleri ve Dosyaya Yazma

logging:
  level:
    root: WARN
    org.springframework.security: DEBUG
  path: /var/logs/
  file: BookWorm.log

Varsayılan logback yapılandırmasını tamamen özelleştirmek isterseniz logback.xml ekleyebilirsiniz.

6) DataSource & Bağlantı Havuzu

Üretimde gömülü H2 yerine kalıcı bir veritabanı kullanacaksanız yalnızca URL ve kimlik bilgilerini tanımlamanız çoğu zaman yeterlidir. Sürücüyü genellikle URL’den otomatik algılar. Aksi halde driver-class-name belirtin.

spring:
  datasource:
    url: jdbc:mysql://localhost/readinglist
    username: dbuser
    password: dbpass
    # driver-class-name: com.mysql.jdbc.Driver

Spring Boot; Tomcat JDBC pool’u varsa onu, yoksa HikariCP, Commons DBCP veya DBCP2 gibi havuzları classpath’e göre kullanır. İsterseniz kendi DataSource bean’inizi manuel tanımlayarak farklı bir pool da seçebilirsiniz.

JNDI ile: spring.datasource.jndi-name=java:/comp/env/jdbc/readingListDS tanımı yapılırsa URL/kullanıcı/parola yok sayılır.

7) Kendi Bean’lerinize Dışarıdan Değer Enjekte Etmek

“Magic string” ve gizli değerleri (ör. affiliate ID, API anahtarı) şablonlara veya koda gömmek yerine dış yapılandırmadan enjekte edin.

7.1. @ConfigurationProperties ile Toplamak

@Component
@ConfigurationProperties("amazon")
public class AmazonProperties {
  private String associateId;
  public String getAssociateId() { return associateId; }
  public void setAssociateId(String associateId) { this.associateId = associateId; }
}
amazon:
  associateId: habuma-20

7.2. Controller’da Kullanmak

@Controller
@RequestMapping("/")
public class ReadingListController {

  private final ReadingListRepository repo;
  private final AmazonProperties amazon;

  public ReadingListController(ReadingListRepository repo, AmazonProperties amazon) {
    this.repo = repo;
    this.amazon = amazon;
  }

  @GetMapping
  public String readersBooks(Reader reader, Model model) {
    List<Book> readingList = repo.findByReader(reader);
    if (readingList != null) {
      model.addAttribute("books", readingList);
      model.addAttribute("reader", reader);
      model.addAttribute("amazonID", amazon.getAssociateId());
    }
    return "readingList";
  }
}

Properties adlandırmada associateId, associate-id ve associate_id eşdeğerdir. Dilediğinizi kullanabilirsiniz.

8) Profiller ile Ortam Bazlı Yapılandırma

Geliştirme, test ve üretimde farklı ayarlar gereklidir. Spring profiles ile bunu temizce yönetebilirsiniz. Aktif profili:

$ java -jar app.jar --spring.profiles.active=production

veya

spring:
  profiles:
    active: production

Properties tarafında application-{profile}.properties / YAML tarafında application-{profile}.yml kullanabilirsiniz. Tek dosyada çoklu profil de mümkündür.

8.1. Tek YAML Dosyada Çoklu Profil

logging:
  level:
    root: INFO
---
spring:
  profiles: development
logging:
  level:
    root: DEBUG
---
spring:
  profiles: production
logging:
  path: /tmp/
  file: BookWorm.log
  level:
    root: WARN

9) Özel Hata Sayfası (Whitelabel’ın Yerine)

Spring Boot varsayılan “Whitelabel Error Page” ile gelir (bkz. Sayfa 72). Projenize uygun, kullanıcı dostu bir hata sayfası için error.html isimli bir şablon koymanız yeterlidir. Şablonda path, message, status, timestamp gibi öznitelikler otomatik sağlanır.

<!-- src/main/resources/templates/error.html -->
<html>
<head><title>Oops!</title></head>
<body>
  <div class="errorPage">
    <h1>Oops! Bir hata oluştu.</h1>
    <p>İstek yolu: <span th:text="${path}"></span></p>
    <p th:text="${'Detay: ' + message}"></p>
  </div>
</body>
</html>
İpucu: Görsel kullanacaksanız src/main/resources/static veya public altına yerleştirin.

10) Hızlı Kontrol Listesi & En İyi Uygulamalar

  • Önce auto-configuration’dan yararlanın, gerekirse manuel bean tanımlayın. (@ConditionalOnMissingBean)
  • Tüm ayarları dışarıdan yönetin; kodda sabit değer bırakmayın. (application.yml önerilir)
  • Geliştirmede spring.thymeleaf.cache=false, üretimde açık kalsın.
  • Port/HTTPS/log seviyelerini properties ile yönetin; profillerle ortam bazlı değiştirin.
  • DataSource için yalnızca URL/kullanıcı/parola girin; havuz seçimini Spring Boot’a bırakın veya istediğiniz pool’u manuel tanımlayın.
  • Whitelabel yerine markalı bir error.html ekleyin; kullanıcıya nazik mesajlar gösterin.

Kaynak: Spring Boot in Action – Bölüm 3 (Customizing Configuration). Bu makaledeki örnek ve açıklamalar ilgili bölümden derlenerek Türkçeye uyarlanmıştır.

Beğendiysen bir çay ısmarlayabilirsin ☕

Bana çay ısmarla

Java ile ilgili yorumlar

Yorum Paylaş

EMail Zorunlu alanlar * *