---
title: 'Bileşen Kapsamları ve Yaşam Döngüsü'
source: 'https://academia.sh/tr/kurslar/kurumsal-uygulama-cercevesi/bilesen-kapsamlari-ve-yasam-dongusu'
course: 'Kurumsal Uygulama Çerçevesi'
language: tr
updated: '2026-08-23T14:25:04+00:00'
license: 'CC BY-SA 4.0'
---

# Bileşen Kapsamları ve Yaşam Döngüsü

Bir kap bileşeninin tekil kalması nesne kabının varsayılan kararı, her istekte yeniden kurulması ise açıkça yazılmış bir kapsam açıklamasından geliyor. Tanınmayan bir kapsam adı hiçbir hata vermiyor — bileşen sessizce tekil olmaktan çıkıyor ve bu ancak iki isteğin kimliğini `==` ile karşılaştırarak görülüyor.

Önceki ders `Bilesen` açıklamasının bir `kapsam` alanı taşıdığını, ama o alanı hiç
kullanmadığını not ederek kapandı: `kap.al(Servis.class)` her çağrıldığında aynı örneği mi
döndürüyor, yoksa her seferinde yeni bir tane mi kuruyor? Bu ders tam bu soruyu açar —
`kapsam` alanının ne yaptığını ve bir kap bileşeninin ne zaman yeniden kurulduğunu ölçer;
ikinci yarısı da bir bileşenin kurulduktan sonra ama kullanılmadan önce çağrılan tek bir
yöntemi — **yaşam döngüsü kancası**nı — inceler.

## Kapsam Kararının Yeri

`Bilesen` açıklaması bir `kapsam` alanı taşıyor ve varsayılan değeri `"tekil"`. `al`
yöntemi bir tip için bu değeri okuyor ve yalnız `tekil.equals("tekil")` doğruysa
`tekiller` haritasına bakıyor; kapsam başka bir değerse (`"her-istekte"` gibi) bu denetim
hiç yapılmıyor ve kod her seferinde `yapici.newInstance(arg)` satırına düşerek yeni bir
örnek kuruyor. `Servis` sınıfı `@Kap.Bilesen` yazıyor, parametre vermeden — bu, `kapsam()`'ın
varsayılan değerinin uygulanacağı anlamına geliyor. `Istek` sınıfı ise `@Kap.Bilesen(kapsam
= "her-istekte")` yazıyor — açık bir değer.

Bu ayrımın doğrulanma yolu **kimlik**tir, değer eşitliği değil: `kap.al(Servis.class) ==
servis` ifadesi iki referansın aynı bellek konumundaki nesneye işaret edip etmediğini
soruyor. Java'da bunu doğrulamanın başka bir kestirme yolu yok — iki `Servis` nesnesinin
alanları aynı olsa bile `==` yalnız gerçekten aynı nesne olduklarında `true` verir. Bu
dersin ölçümü kimlik karmasını (`hashCode()` çıktısını) hiçbir yerde basmıyor, çünkü o
değer koşumdan koşuma değişebilir ve kendisi bir kanıt değil; kanıt yalnız `==`
karşılaştırmasının sonucu.

- **CK11.** Kapsam denetimi yalnız `tekil` değeri için `tekiller` haritasına bakıyor; başka
  her değer "her seferinde yeniden kur" anlamına geliyor, ayrı bir liste ya da sayaç
  tutulmuyor.
- **CK12.** Kimlik yalnız `==` ile okunuyor; hiçbir nesnenin kimlik karması ya da bellek
  adresi basılmıyor.
- **CK13.** Kurulum yöntemi (`Kur` açıklaması) yapıcı çalıştıktan ve ayar alanları
  dolduktan **sonra** çağrılıyor; nesne zaten tamamen kurulmuş durumda.
- **CK14.** Bir kap bileşeninde en çok bir kurulum yöntemi bulunuyor; bu ölçüm birden çok
  `Kur` işaretli yöntemi olan bir sınıfı denemiyor.
- **CK15.** Tanınmayan bir kapsam adı (`"tanimsiz-kapsam"` gibi) derleme zamanında
  yakalanmıyor — `kapsam()` bir dizgi döndürüyor, kap onu yalnız çalışma zamanında
  `"tekil"`'e eşitliyor.

```java
// Kap.java — bir kap bileseninin kapsamini ve kurulum sirasini kaynakta ne dogurdu: bir aciklama mi, kabin varsayilani mi
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;

public class Kap {

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE)
    @interface Bilesen { String kapsam() default "tekil"; }

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
    @interface Kur {}

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD)
    @interface Ayar { String ad(); String varsayilan(); }

    static int aciklama = 0, varsayilan = 0;
    static int sessiz = 0;

    static void gozle(String davranis, String kaynak) {
        if (kaynak.equals("varsayilan")) varsayilan++; else aciklama++;
        System.out.printf("%-38s %s%n", davranis, kaynak);
    }

    static void kural(String ad, String sonuc) {
        if (sonuc.equals("sessiz")) sessiz++;
        System.out.printf("%-38s %s%n", ad, sonuc);
    }

    static void ozet() {
        System.out.printf("davranis: %d aciklama, %d varsayilan%n", aciklama, varsayilan);
        System.out.printf("kusur   : %d sessiz%n", sessiz);
    }

    final Map<Class<?>, Object> tekiller = new HashMap<>();
    final Map<String, String> ayarlar = new LinkedHashMap<>();
    final List<String> gunluk = new ArrayList<>();

    final Map<Class<?>, Class<?>> baglar = new HashMap<>();

    Kap ayar(String ad, String deger) { ayarlar.put(ad, deger); return this; }

    Kap bagla(Class<?> arayuz, Class<?> gerceklestirim) { baglar.put(arayuz, gerceklestirim); return this; }

    Object al(Class<?> tip) throws Exception {
        if (tip.isInterface()) {
            Class<?> gerceklestirim = baglar.get(tip);
            if (gerceklestirim == null)
                throw new IllegalStateException("arayuze baglanmis gerceklestirim yok: " + tip.getSimpleName());
            return al(gerceklestirim);
        }
        Bilesen b = tip.getAnnotation(Bilesen.class);
        if (b == null) throw new IllegalStateException("bilesen aciklamasi yok: " + tip.getSimpleName());
        boolean tekil = b.kapsam().equals("tekil");
        if (tekil && tekiller.containsKey(tip)) return tekiller.get(tip);

        Constructor<?> yapici = tip.getDeclaredConstructors()[0];
        yapici.setAccessible(true);
        Object[] arg = new Object[yapici.getParameterCount()];
        for (int i = 0; i < arg.length; i++) arg[i] = al(yapici.getParameterTypes()[i]);
        Object ornek = yapici.newInstance(arg);

        for (Field f : tip.getDeclaredFields()) {
            Ayar a = f.getAnnotation(Ayar.class);
            if (a == null) continue;
            f.setAccessible(true);
            f.set(ornek, ayarlar.getOrDefault(a.ad(), a.varsayilan()));
        }
        for (Method m : tip.getDeclaredMethods()) {
            if (m.isAnnotationPresent(Kur.class)) { m.setAccessible(true); m.invoke(ornek); gunluk.add("kur:" + tip.getSimpleName()); }
        }
        if (tekil) tekiller.put(tip, ornek);
        return ornek;
    }

    public static void main(String[] args) throws Exception {
        Kap kap = new Kap().bagla(Depo.class, BellekDepo.class).ayar("depo.baslangic", "dolu");

        Servis servis = (Servis) kap.al(Servis.class);
        Kap.gozle("ayni ornegin donmesi", kap.al(Servis.class) == servis ? "varsayilan" : "aciklama");
        Kap.gozle("her istekte yeni ornek", kap.al(Istek.class) != kap.al(Istek.class) ? "aciklama" : "varsayilan");
        Kap.gozle("kurulum yonteminin cagrilmasi", kap.gunluk.contains("kur:BellekDepo") ? "aciklama" : "varsayilan");

        BellekDepo elle = new BellekDepo();
        System.out.println("kapla kurulanin durumu   : " + ((BellekDepo) servis.depo).durum);
        System.out.println("elle kurulanin durumu    : " + elle.durum);

        Kap k2 = new Kap();
        Object y1 = k2.al(YanlisKapsam.class), y2 = k2.al(YanlisKapsam.class);
        Kap.kural("kapsam adi taninmiyor", y1 == y2 ? "etkisiz" : "sessiz");

        Kap.ozet();
    }
}

interface Depo { String oku(); }

@Kap.Bilesen
class BellekDepo implements Depo {
    @Kap.Ayar(ad = "depo.baslangic", varsayilan = "bos") String baslangic;
    String durum = "kurulmadi";
    @Kap.Kur void hazirla() { durum = "hazir:" + baslangic; }
    public String oku() { return durum; }
}

@Kap.Bilesen
class Servis {
    final Depo depo;
    Servis(Depo depo) { this.depo = depo; }
    String rapor() { return depo.oku(); }
}

@Kap.Bilesen(kapsam = "her-istekte")
class Istek { }

@Kap.Bilesen(kapsam = "tanimsiz-kapsam")
class YanlisKapsam { }
```

```
ayni ornegin donmesi                   varsayilan
her istekte yeni ornek                 aciklama
kurulum yonteminin cagrilmasi          aciklama
kapla kurulanin durumu   : hazir:dolu
elle kurulanin durumu    : kurulmadi
kapsam adi taninmiyor                  sessiz
davranis: 2 aciklama, 1 varsayilan
kusur   : 1 sessiz
```

Bu payın birinci dersi aynı soruyu on iki davranış ve dört kusur üzerinden ölçmüş, `3 çağrı,
6 açıklama, 3 varsayılan` ve `1 hata, 2 sessiz, 1 etkisiz` toplamına varmıştı; bu ders o
çekirdeğin yalnız kapsam ve yaşam döngüsü diliminde kalıyor — `bagla` ile enjekte edilen
bağımlılık ve `dene`'nin ölçtüğü bağlanmamış arayüz burada yeniden ölçülmüyor.

## Tekil, Varsayılanın Kendisi

`ayni ornegin donmesi` satırı `varsayilan` çıkıyor çünkü `Servis`'in kaynak dosyasında
kapsamı belirten hiçbir sözcük yok. `@Kap.Bilesen` çıplak yazılıyor, parantezsiz —
`kapsam()`'ın `default "tekil"` değeri devreye giriyor ve bu değeri veren satır `Servis.java`
değil, `Kap.java`'daki açıklama tanımı. Bu payın birinci dersinde de görülen bir örüntü
burada tam ortasına oturuyor: kaynağı okuyan biri `Servis`'in tekil olduğunu **bilemez**,
çünkü kaynak bunu hiç söylemiyor; yalnız kabın kuralını (varsayılan kapsamın tekil olduğunu)
önceden bilen biri bu sonucu tahmin edebilir.

`her istekte yeni ornek` satırı ise tam tersi: `açıklama` çıkıyor, çünkü `Istek` sınıfı
`kapsam = "her-istekte"` yazarak varsayılan değeri **açıkça bastırıyor**. Bu, bir Java
yöntem yeniden tanımlaması değil, bir varsayılan değerin bir açıklama bağımsız
değişkeniyle üzerine yazılması — `kap.al(Istek.class) != kap.al(Istek.class)` iki ayrı
çağrının iki ayrı nesne döndürdüğünü doğruluyor, ve bu fark kaynakta gerçekten yazan bir
sözcükten geliyor: `"her-istekte"`.

## Kurulum Yöntemi: Nesne Hazır Olduktan Sonra

`BellekDepo` sınıfının `hazirla()` yöntemi `@Kap.Kur` taşıyor ve gövdesi tek satır: `durum =
"hazir:" + baslangic;`. Bu yöntemin ne zaman çağrılacağı `al` yönteminin sırasından
belirleniyor: önce yapıcı çalışıyor (`ornek` oluşuyor), sonra `Ayar` işaretli alanlar
dolduruluyor (`baslangic` alanına değer yazılıyor), **sonra** `Kur` işaretli yöntemler
çağrılıyor. Bu sıra rastgele değil — `hazirla()` çağrıldığında `baslangic` alanı zaten dolu
olmasaydı, `durum` değeri `"hazir:null"` gibi anlamsız bir şey taşırdı. Kap bu sırayı
zorluyor, ve kaynakta bu sırayı belirten hiçbir sayı ya da açıklama parametresi yok — sıra
`al` yönteminin kod satırlarının kendi sırası.

Kurulum yönteminin gerçekten çağrıldığı `kap.gunluk` listesiyle doğrulanıyor:
`gunluk.add("kur:" + tip.getSimpleName())` satırı her çağrıdan sonra bir kayıt bırakıyor, ve
`kurulum yonteminin cagrilmasi` satırı bu kaydın varlığını arıyor. Burada gerçek bir saat
ya da sıra numarası tutulmuyor — yalnız "bu yöntem çağrıldı mı" sorusuna cevap veren bir
dizgi listesi. Elle kurulan `BellekDepo` bu kaydı hiç almıyor: `elle.durum` alanı sonsuza
kadar `"kurulmadi"` kalıyor, çünkü `hazirla()`'yı çağıracak taraf yalnız kap, ve elle kurulan
nesne kabın hiç görmediği bir nesne.

Kapsam ile kurulum yöntemi birbirinden bağımsız görünen iki mekanizma, ama aralarındaki
ilişki `al` yönteminin kendi sırasından geliyor: kurulum bloğu, tekil önbelleğe yazmadan
**önce** çalışıyor, ve bu blok kapsamdan habersiz — hangi kapsamda olursa olsun her **yeni
kurulan** örnek için bir kez koşuyor. `Istek` sınıfının hiçbir `Kur` işaretli yöntemi
olmadığı için bu ölçüm bunu doğrudan göstermiyor, ama düzenek şunu ima ediyor: `her-istekte`
kapsamlı bir bileşenin bir kurulum yöntemi olsaydı, o yöntem her istekte yeniden çağrılırdı
— çünkü `her-istekte` kapsamı her isteği yeni bir kurulmaya çeviriyor, ve her kurulma kendi
kurulum çağrısını tetikliyor. Tekil bir bileşende kurulum yöntemi ömür boyu **tam bir kez**
çalışıyor; her-istekte bir bileşende (varsayımsal olarak) her istekte yeniden çalışırdı.
Kapsam ve kurulum yöntemi kaynakta iki ayrı açıklama olarak duruyor, ama aralarındaki bu
ilişki hiçbir yerde yazmıyor — yalnız `al` yönteminin kod sırasını okuyarak çıkarılabiliyor.

## Neden Ayrı Bir Adım

Kurulum yöntemini yapıcının kendisine koymak neden işe yaramazdı? `BellekDepo`'nun yapıcısı
yok — Java, hiçbir yapıcı yazılmadığında derleyicinin ürettiği parametresiz varsayılan
yapıcıyı kullanıyor. `hazirla()`'yı bu yapıcıya taşımak mümkün değil, çünkü Java'da bir
yapıcının gövdesi yalnız kendi sınıfının yazdığı koddur; kabın `Ayar` alanlarını yapıcıdan
**sonra** doldurduğu düzenekte, yapıcı çalıştığı anda `baslangic` alanı henüz `null`.
Kurulum mantığını yapıcıya koysaydık, o mantık her zaman boş bir değer görürdü.

Bu, kap bileşenlerinin yaşam döngüsünü iki ayrı aşamaya bölmenin gerekçesi: **kurma**
(yapıcının çalışması, nesnenin bellekte var olması) ve **hazırlama** (ayarların
yerleşmesi, bağımlı kaynakların açılması, hazırlık mantığının çalışması). Yapıcı yalnız
birinci aşamayı garanti ediyor; ikinci aşama için ayrı bir kanca gerekiyor, ve bu kanca
tam olarak `Kur` açıklamasının işi. Elle kurulan bir nesnede bu ikinci aşama hiç
gerçekleşmiyor — `elle` nesnesi birinci aşamadan geçti (yapıcı çalıştı, nesne var), ama
ikinci aşamaya hiç girmedi.

`Istek` sınıfının hiçbir alanı ve hiçbir kurulum yöntemi yok; her istekte yeni bir örnek
kurulduğunda kap onu `tekiller` haritasına hiç yazmıyor, dolayısıyla hiçbir referans
tutmuyor. Bu ölçümde `Istek` örneklerinin sayısı ayrıca sayılmıyor, çünkü ölçülen şey süre
ya da bellek değil — yalnız iki isteğin aynı nesneyi mi, ayrı nesneleri mi aldığı.

## Sınırlayıcı Ölçüm: Tanınmayan Bir Kapsam Adı

`YanlisKapsam` sınıfı `@Kap.Bilesen(kapsam = "tanimsiz-kapsam")` taşıyor — kabın tanıdığı
tek değer `"tekil"`, ama açıklama bağımsız değişkeni bir dizgi, ve derleyici bu dizginin
kabın anladığı bir değer olup olmadığını denetlemiyor. Sonuç `al` yönteminin `boolean tekil
= b.kapsam().equals("tekil");` satırında ortaya çıkıyor: `"tanimsiz-kapsam".equals("tekil")`
`false` döndürüyor, `tekil` değişkeni `false` oluyor, ve kod tekil denetimini hiç yapmadan
her seferinde yeni bir örnek kuruyor.

```
Object y1 = k2.al(YanlisKapsam.class), y2 = k2.al(YanlisKapsam.class);
Kap.kural("kapsam adi taninmiyor", y1 == y2 ? "etkisiz" : "sessiz");
```

`y1 == y2` `false` çıkıyor — iki istek iki ayrı nesne. Bu, kural satırının `"sessiz"`
sınıfına düşmesinin nedeni: hiçbir istisna fırlamıyor, hiçbir günlük satırı "bilinmeyen
kapsam" demiyor, program sorunsuz çalışmaya devam ediyor. Yalnız beklenen davranış
(tekil kalmak) sessizce kayboluyor. Bu kusuru fark etmenin tek yolu, iki isteğin kimliğini
`==` ile karşılaştırmak — değer eşitliğine bakan bir denetim (iki nesnenin alanları aynı mı)
hiçbir şey yakalamaz, çünkü `YanlisKapsam`'ın hiç alanı yok, ikisi de "eşit" görünür. Kusur
ancak kimliğe bakan bir gözle görünüyor, ve bu ders boyunca kimlik hep `==` ile okundu,
hiçbir zaman bir kimlik karması basılmadı.

Bu, önceki dersin bağlanmamış arayüz gözlemiyle aynı ailede bir tasarım tercihi: kap orada
da bağımlılık grafiğini kurulurken taramıyor, yalnız istendiğinde denetliyordu. Burada da
kapsam adı `Bilesen` açıklamasına yazıldığı anda değil, `al` çağrıldığı anda okunuyor, ve
tanınan tek değer bir dizgi eşitliği ile karşılaştırılıyor — küçük bir yazım farkı (`"tekil"`
yerine `"Tekil"` ya da `"tanimsiz-kapsam"`) derleyiciye hiç görünmeden geçiyor. İki ders de
aynı sonuca varıyor: kabın erken uyarı vermemesi bir eksiklik değil, bu modelin bilinçli
sınırı — doğrulama, kaynağı okumakla değil, kapsanan davranışı gerçekten koşturmakla
mümkün.

## Özet

- Tekil kapsam kabın varsayılanı; kaynakta bunu belirten hiçbir sözcük olmasa bile
  `Bilesen`'in `kapsam()` değeri devreye giriyor.
- Bir kap bileşenini her istekte yeniden kurdurmak açık bir `kapsam = "her-istekte"`
  bağımsız değişkeni gerektiriyor — bu, kaynakta gerçekten yazan bir sözcükten doğan bir
  davranış.
- Kurulum yöntemi (yaşam döngüsü kancası) yapıcı ve ayar alanları tamamlandıktan sonra, tam
  bir kez çağrılıyor; sırayı belirleyen `al` yönteminin kendi kod sırası.
- Elle kurulan bir nesne kurulum yöntemini hiç almıyor; alan hep başlangıç değerinde
  kalıyor.
- Tanınmayan bir kapsam adı hiçbir hata vermiyor — bileşen sessizce tekil olmaktan çıkıyor
  ve bu ancak `==` ile yapılan bir kimlik karşılaştırmasıyla görünüyor.

## Sonraki Adım

`hazirla()` yöntemi `baslangic` alanına yazılmış değeri okuyarak `durum` alanını dolduruyor,
ve bu `baslangic` alanı da kendi başına bir açıklamayla besleniyor: `@Kap.Ayar(ad =
"depo.baslangic", varsayilan = "bos")`. Bu ders o değerin nereden geldiğini hiç sormadı —
yalnız kurulum sırasında dolu olduğunu varsaydı. Sıradaki ders tam bu soruyu açar: bir kap
bileşeninin ayar değeri, kaynakta hiç görünmeyen bir öncelik sırasından hangi kaynağı
kazanıyor, ve bu sıra neden dışarıdan bakan biri için görünmez.
