---
title: 'Bağımlılık Enjeksiyonu'
source: 'https://academia.sh/tr/kurslar/kurumsal-uygulama-cercevesi/bagimlilik-enjeksiyonu'
course: 'Kurumsal Uygulama Çerçevesi'
language: tr
updated: '2026-08-23T14:25:04+00:00'
license: 'CC BY-SA 4.0'
---

# Bağımlılık Enjeksiyonu

Bir nesne kabı bir bağımlılığı yapıcı üzerinden sağladığında bu bir açıklamadan doğuyor; aynı bağımlılık elle verildiğinde kaynakta duran bir çağrıdan doğuyor — ve aynı sınıf ikisiyle de çalışıyor. Arayüze bağlanmış bir gerçekleştirim yoksa kap hemen bir istisna fırlatıyor, ama kap kurulurken değil, ilk istekte.

Önceki ders `new Servis(elle)` satırının kabın içindeki bir mekanizmayı elle taklit ettiğini
söyleyerek kapandı: bir bağımlılığı bir yapıcıya vermek. `Servis` sınıfının tek yapıcısı bir
`Depo` parametresi alıyor, ve nesne kabı `Servis`'i kurarken bu parametreyi kendi başına
çözüyor — kaynakta hiçbir `new BellekDepo()` yazmadan. Bu dersin sorusu şu: bu çözme işlemi
gerçekten bir **enjeksiyon** mu, yoksa yalnız kurmanın başka bir adı mı? Ve daha önemlisi:
aynı `Servis` sınıfı, bağımlılığı elle verildiğinde de çalışıyor mu?

**Bağımlılık enjeksiyonu**nun kendisi bu kursta yeni bir fikir değil — Tasarım Kalıpları
kursu onu ilke–ayrıntı ayrımını sağlayan bir kalıp olarak, sınanabilir tasarımın temel taşı
diye kurdu. Bu ders o kalıbı öğütlemez; kabın onu **hangi düzenekle** uyguladığını ve
kaynakta ne bıraktığını ölçer. Sorulan şey aynı: bu davranışı kaynakta bir çağrı mı doğurdu,
bir açıklama mı, yoksa hiçbiri mi?

## Yapıcının İçini Kap Dolduruyor

Nesne kabının `al` yöntemi bir tip istendiğinde önce o tipin yapıcısını buluyor, sonra
yapıcının parametre tiplerini teker teker geziyor ve her biri için **kendi kendini tekrar
çağırıyor**: `arg[i] = al(yapici.getParameterTypes()[i]);`. `Servis`'in tek parametresi
`Depo` olduğu için bu döngü bir kez çalışıyor ve `al(Depo.class)`'ı çağırıyor; `Depo` bir
arayüz olduğundan kap onu `baglar` haritasında arıyor, bulduğu `BellekDepo`'yu kuruyor ve
geri döndürüyor. Sonuçta `yapici.newInstance(arg)` çağrıldığında `arg[0]` zaten hazır bir
`BellekDepo` örneği — kaynakta bu değeri dolduran hiçbir satır yok, doldurulma işi tamamen
bu özyinelemeli döngünün içinde oluyor.

Bu, yapıcı temelli enjeksiyonun tanımı: bağımlılık, nesne kurulmadan **önce** çözülüyor ve
yapıcıya bir bağımsız değişken olarak geçiriliyor. Alan üzerinden enjeksiyon (nesne önce
kurulup sonra bir alanına yansımayla değer yazılması) bu payda hiç kurulmuyor — kap yalnız
yapıcı parametrelerini dolduruyor, çünkü `Servis`'in `depo` alanı `final` ve yapıcıda
atanıyor. Bu kısıt bilinçli: `final` bir alan kurulduktan sonra değiştirilemez, bu yüzden
`Servis`'in bağımlılığı olmadan var olması mümkün değil — derleyicinin kendisi bunu
zorluyor, kabın nezaketi değil.

`yapici.setAccessible(true)` satırı ayrı bir gözleme değer. `Servis`'in yapıcısı hiçbir
erişim belirteci taşımıyor, yani paket içi görünürlükte; normal bir `new Servis(depo)`
çağrısı da zaten aynı paketten geldiği için bu görünürlükle çalışırdı. Ama kabın kendisi
`Servis`'i genel amaçlı bir `Class<?>` nesnesi üzerinden, hangi paketten geldiğini
önceden bilmeden kuruyor; yansımanın normal erişim denetimi bu durumda araya girer ve
`setAccessible(true)` çağrısı olmadan `IllegalAccessException` fırlatırdı. Bu satır kabın
"her kap bileşenini, görünürlüğü ne olursa olsun kurabilme" garantisinin kaynağı — ve bu
garanti de kaynakta hiçbir zaman görünmeyen, yalnız kabın kendi kodunda duran bir karar.

Kabın yapıcı seçimi de kendi başına bir varsayım taşıyor: `al` yöntemi hiçbir seçim
yapmıyor, doğrudan `tip.getDeclaredConstructors()[0]` diyor — sınıfın **tam olarak bir**
yapıcısı olduğunu, birden çoksa bile ilkinin doğru olduğunu baştan kabul ediyor. `Servis`
ve `BellekDepo`'nun ikisi de tek yapıcılı olduğu için bu ölçüm bu varsayımı hiç zorlamıyor,
ama kabın kendisi bunu hiçbir yerde denetlemiyor. İkinci bir yapıcı eklenseydi —
`Servis(Depo depo, String etiket)` gibi bir aşırı yükleme — `getDeclaredConstructors()`'ın
döndürdüğü dizinin sırası Java dil belirtiminde **garanti edilmiyor**; kap hangi yapıcıyı
seçeceğini önceden bilemezdi, ve seçilen yapıcının bir parametresi kap bileşeni olarak
çözülemeyen bir tip taşısaydı (`String` gibi) özyinelemeli `al` çağrısı bir istisna
fırlatırdı. Bu, dersin ölçmediği ama modelin taşıdığı bir kırılganlık: yapıcı temelli
enjeksiyon, sınıfın **tek** bir kurulma yolu olduğu varsayımına dayanıyor, ve bu varsayım
kaynakta açıkça yazmıyor — yalnız sınıfın kaç yapıcı tanımladığına bakarak anlaşılabiliyor.

Bu payın ölçtüğü enjeksiyon aynı zamanda dar bir enjeksiyon: yapıcı yalnız başka bir kap
bileşenini ya da bir arayüzü isteyebiliyor, `String`, `int` gibi çıplak bir değeri değil.
Değer türünden bir bağımlılığı doldurmak ayrı bir düzenek — `Ayar` açıklaması — gerektiriyor,
ve bu ölçüm onu hiç kurmuyor; `BellekDepo`'nun kendi verisini sabit döndürmesi de tam bu
yüzden.

- **CK6.** Yapıcı parametre çözümü derinlik öncelikli: bir parametrenin kendi bağımlılığı
  varsa, o da aynı `al` çağrısıyla önce çözülüyor.
- **CK7.** `Servis`'in `depo` alanı `final`; bu, bağımlılığın yapıcı dışında hiçbir yoldan
  atanamayacağını derleme zamanında garanti ediyor.
- **CK8.** Aynı `BellekDepo` örneği hem kap yoluyla hem elle kurulup aynı arayüz üzerinden
  çağrılıyor; ölçülen fark kurulma biçimi, çağrı sözleşmesi değil.
- **CK9.** `baglar` haritası yalnız arayüz–gerçekleştirim eşleşmesi tutuyor; hangi
  gerçekleştirimin seçileceği kararı kaynakta değil, `bagla` çağrısının kendisinde.
- **CK10.** Bağlanmamış bir arayüz istendiğinde kap, hangi tipin eksik olduğunu adıyla
  söyleyen bir istisna fırlatıyor; bu istisna kapsanmıyor, ilk isteği yapan tarafa çıkıyor.

```java
// Kap.java — bir bagimliligi kaynakta bir cagri mi bir aciklama mi dogurdu
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;

public class Kap {

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE)
    @interface Bilesen {}

    static int cagri = 0, aciklama = 0;

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

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

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

    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());

        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]);
        return yapici.newInstance(arg);
    }

    String dene(Class<?> tip) {
        try { al(tip); return "tamam"; }
        catch (Exception e) { return e.getClass().getSimpleName(); }
    }

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

        Servis servis = (Servis) kap.al(Servis.class);
        Kap.gozle("bagimliligin saglanmasi", servis.depo != null ? "aciklama" : "cagri");

        BellekDepo elle = new BellekDepo();
        Kap.gozle("dogrudan yontem cagrisi", "cagri");
        Kap.gozle("bagimliligin elle verilmesi", "cagri");

        Servis servisElle = new Servis(elle);
        System.out.println("kap yoluyla donen deger  : " + servis.rapor());
        System.out.println("elle yoluyla donen deger : " + servisElle.rapor());

        Kap.ozet();
    }
}

interface Depo { String oku(); }

@Kap.Bilesen
class BellekDepo implements Depo {
    public String oku() { return "veri"; }
}

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

```
bagimliligin saglanmasi                aciklama
dogrudan yontem cagrisi                cagri
bagimliligin elle verilmesi            cagri
kap yoluyla donen deger  : veri
elle yoluyla donen deger : veri
davranis: 2 cagri, 1 aciklama
```

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 bağımlılık sağlama diliminde kalıyor.

## İki Yol, Aynı Sözleşme

`bagimliligin saglanmasi` satırı `aciklama` çıkıyor çünkü `servis.depo` alanı hiçbir kaynak
satırı olmadan doluyor — kap onu yapıcıya verdi. `bagimliligin elle verilmesi` satırı `cagri`
çıkıyor çünkü aynı alan `new Servis(elle)` çağrısında kaynakta duran bir bağımsız değişken
üzerinden doluyor. Aradaki fark yalnız *nereden* geldiği; `Servis` sınıfının kendisi hangi
yoldan kurulduğunu bilmiyor ve bilmesi de gerekmiyor — `depo` alanı ikisinde de aynı `Depo`
arayüzüne bakıyor.

Bunun sınanabilirlikle ilgisi doğrudan: `servis.rapor()` ve `servisElle.rapor()` ikisi de
çalışıyor, ikisi de aynı `"veri"` dizgisini döndürüyor, ve `dogrudan yontem cagrisi` satırı
`elle.oku()`'yu kap hiç araya girmeden doğrudan çağırarak bunu ayrıca kanıtlıyor — `Servis`'i
elle kurup test etmek mümkün. Tasarım Kalıpları kursunun kurduğu ilke burada somutlaşıyor:
`Servis` bir arayüze bağımlı, belirli bir gerçekleştirime değil, bu yüzden testte gerçek
`BellekDepo` yerine sahte bir `Depo` gerçekleştirimi geçirmek `Servis`'in tek satırını bile
değiştirmeden mümkün. Kap bu ilkeyi **uygulamıyor** — `Servis`'in kendisi zaten bu ilkeye
göre yazılmış; kap yalnız hangi gerçekleştirimin hangi arayüze karşılık geldiğini `bagla`
çağrısıyla kaydediyor ve doğru anda geri veriyor.

`baglar` haritasının kendisi de bir ölçüm noktası: `Kap bagla(Class<?> arayuz, Class<?>
gerceklestirim)` yöntemi kaynakta açıkça çağrılıyor — `new Kap().bagla(Depo.class,
BellekDepo.class)` bir **çağrı**, açıklama değil. Hangi gerçekleştirimin seçileceği kararı
sınıfların üzerinde değil, kabı kuran kodun içinde duruyor. Bu, dersin ikinci gözlemi:
enjeksiyonun kendisi açıklamadan doğsa da, *hangi* gerçekleştirimin enjekte edileceği kararı
kaynakta gerçekten yazan bir satırdan geliyor.

Bu ayrımın önemi `BellekDepo`'nun yerine ikinci bir `Depo` gerçekleştirimi konduğunda
görünür oluyor. `Servis` sınıfı yalnız `Depo` arayüzünü anıyor — yapıcı imzasında,
`rapor()` gövdesinde, hiçbir yerde `BellekDepo` adı geçmiyor. `bagla(Depo.class,
BaskaDepo.class)` satırı `bagla(Depo.class, BellekDepo.class)` ile değiştirilse `Servis`'in
kaynak dosyasında tek bir karakter bile değişmiyor; değişen tek şey kabı kuran satır.
Tasarım Kalıpları kursunun ayırdığı **ilke** ile **ayrıntı** burada tam bu sınırda duruyor:
ilke `Depo` arayüzü, ayrıntı `BellekDepo` sınıfı, ve aradaki bağı kuran karar `Servis`'in
içinde değil kabın dışında yazılıyor. Bu payın ölçtüğü şey bu kararın kendisinin de kaynakta
bir iz bıraktığı — yalnız `Servis`'in içinde değil.

Küçük bir yan not: `baglar` bir harita olduğu için aynı arayüze iki kez `bagla` çağrılırsa
ikinci çağrı birincisini sessizce değiştiriyor, ne bir istisna ne bir uyarı. Bu ders bunu
ayrıca ölçmüyor, ama üçüncü dersin kapsam ölçümüyle aynı aileden bir gözlem: bir haritaya
yazmak, bir listeye eklemekten farklı bir kural taşıyor.

## Sınırlayıcı Ölçüm: Bağlanmamış Bir Arayüz

Yukarıdaki kurulumda `Depo` her zaman `BellekDepo`'ya bağlandı. Bu bağlama atlanırsa ne
olur?

```java
// ArayuzHatasi.java — arayuze baglanmis gerceklestirim yoksa kap hata veriyor, ve tam ilk istekte
public class ArayuzHatasi {
    public static void main(String[] args) throws Exception {
        Kap baglanmamis = new Kap();
        System.out.println("kap kuruldu, henuz hicbir istek yapilmadi");
        System.out.println("bagli gerceklestirim sayisi           : " + baglanmamis.baglar.size());
        String sonuc = baglanmamis.dene(Servis.class);
        System.out.println("Servis istendiginde firlayan istisna  : " + sonuc);
    }
}
```

```
kap kuruldu, henuz hicbir istek yapilmadi
bagli gerceklestirim sayisi           : 0
Servis istendiginde firlayan istisna  : IllegalStateException
```

`new Kap()` satırı hiçbir denetim yapmıyor — `bagla` hiç çağrılmamış olsa bile kap sorunsuz
kuruluyor, `baglar` haritası boş kalıyor ve hiçbir uyarı çıkmıyor. Kusur, `Servis` gerçekten
istendiğinde düşüyor: `al(Servis.class)` yapıcı parametresini çözmeye çalışırken `al
(Depo.class)`'a giriyor, `Depo`'nun bir arayüz olduğunu görüyor, `baglar.get(Depo.class)`
`null` döndürüyor ve kap adı açıkça anan bir `IllegalStateException` fırlatıyor. Bu, kursun
dört kusurundan tek **gürültülü** olanı — geri kalan üçü (yanlış yazılmış ayar adı,
tanınmayan kapsam adı, arayüzsüz sınıfa konan sarmalama işareti) sessiz ya da etkisiz
kalıyor, ama bağlanmamış bir arayüz kabı susturmuyor.

Zamanlama önemli: hata **kap kurulurken değil, ilk istekte** düşüyor. Bir program `new
Kap().bagla(...)` satırlarını çalıştırıp hiçbir hata almadan ilerleyebilir, sonra dakikalar
sonra ilk kez `Servis` istendiğinde çökebilir. Kabın kurulma anı ile bağımlılık grafiğinin
gerçekten doğrulandığı an aynı değil — bu ayrım, kap bileşenleri arasında eksik bir bağ
varsa onu ne zaman öğreneceğinizi belirliyor.

Bu ölçümdeki `Kap` bilerek en basit hâliyle bırakıldı: `al` yöntemi eksik bir bağlamayı
yalnızca kendisi istendiğinde fark ediyor, kabın kurulduğu anda bütün bağımlılık grafiğini
önceden tarayıp doğrulamıyor. Sonuç olarak eksik bir bağlama, programın o yolu hiç
çalıştırmadığı sürece fark edilmeden kalabiliyor — derleyicinin yakalayabileceği bir
tip uyuşmazlığından farklı olarak, bu kusur yalnızca ilgili kod yolu koşturulduğunda ortaya
çıkıyor.

Bu tercih bir ödünç taşıyor: erken doğrulama (kap kurulurken bütün grafiği tarayıp eksik
bağlamaları önceden bulmak) programın en başında çökmeyi göze alır ama hatayı üretime
çıkmadan yakalar; geç doğrulama (bu ölçümün seçtiği yol) kabın kurulmasını hızlı ve basit
tutar ama eksik bir bağ, o kod yolu hiç koşturulmadığı sürece fark edilmeden kalabilir. Bu
ders ikinci yolu modelliyor, çünkü kabın kendisi de kaynakta yazmayan bir karardan ibaret —
`al` yönteminin ne zaman doğrulama yaptığı da, tıpkı bir bağımlılığın nereden geldiği gibi,
yalnız kabın kendi kodunu okuyarak anlaşılabilir bir seçim.

## Özet

- Yapıcı temelli enjeksiyon, bir bağımlılığı nesne kurulmadan önce çözüp yapıcıya bağımsız
  değişken olarak veren düzenektir; kaynakta bu değeri dolduran hiçbir atama yoktur.
- Aynı sınıf hem kapla hem elle kurulabilir ve ikisi de çalışır — bağımlılık bir arayüze
  bağlı olduğu sürece kap, sınanabilirliği bozmadan araya giriyor.
- Hangi gerçekleştirimin hangi arayüze enjekte edileceği kararı kaynakta gerçekten duran
  bir `bagla` çağrısından geliyor; bu, açıklamadan değil çağrıdan doğan bir davranış.
- Bağlanmamış bir arayüz istendiğinde kap hemen ve adıyla bir istisna fırlatır — bu, dört
  kusurdan tek gürültülü olanı.
- Bu hata kabın kurulduğu satırda değil, bağımlılığın gerçekten istendiği ilk anda düşer;
  kurulma ile doğrulama aynı zamanda olmaz.

## Sonraki Adım

Bu ders `Servis`'in bağımlılığını nereden aldığını ölçtü, ama `Servis`'in kendisinin kap
tarafından ne zaman yeniden kurulduğunu hiç sormadı — `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?
`Bilesen` açıklamasının bir `kapsam` alanı var, ve bu ders onu hiç kullanmadı; birinci
derste görülen `Servis`'in tekil kalması da, `Istek`'in her istekte yeniden kurulması da
tam bu alanın değerinden geliyordu. Sıradaki ders bu alanı açar: bir kap bileşeni ne zaman
aynı kalır, ne zaman yeniden kurulur, ve kurulum yöntemi tam olarak hangi anda çağrılır.
