İçeriğe geç

Annotation ve Reflection — Spring'in Sihri Nasıl Çalışır?

Orta 9 dk Çok sık karşılaşılır

Önce şunu oku: Interface ve Abstract Class — Rol mü, İskelet mi?

30 saniyede özet

Annotation sınıfa yapıştırılmış bir nottur ve kendi başına hiçbir şey yapmaz. Reflection, programın çalışırken kendi sınıflarına bakıp bu notları okumasıdır; Spring'in bütün 'sihri' bu ikisinin birleşimidir.

Bir depoda kutuların üstüne yapışkan notlar yapıştırıyorsun: “kırılır”, “önce bunu gönder”. Notlar kutuyu değiştirmez; onları okuyan depo görevlisi davranışını değiştirir.

Spring’in “sihir” gibi görünen her yeri, tam olarak bu iki şeyin birleşimidir: bir not ve o notu okuyan biri.

Annotation bir nottur; onu okuyan Spring işe koyulmasa hiçbir şey olmazdı.
Adım adım oku
  1. Rafta sıradan üç sınıf duruyor.
  2. İkisinin üstüne not yapıştırılıyor: @Service ve @Repository. Üçüncüsünde not yok.
  3. Notlar kendi başına hiçbir şey yapmaz.
  4. Spring rafı tarar, notlu sınıfların nesnelerini kurar; notsuz sınıfa dokunmaz.
  1. Bayt: @Service yazdım, hiçbir yerde new demedim, ama nesnem hazır! Bu sihir mi?

  2. Sen: Bir de kendi notumu yazdım, ama hiçbir şey olmadı.

  3. Bayt: Çünkü notu okuyan kimse yok. Spring @Service'i okuyor, senin notunu okuyan henüz yok.

  4. Bayt: O zaman notu okuyan kısmı kendimiz yazalım. Sihrin nasıl yapıldığını göreceksin.

Annotation bir not, bir komut değil

@Override, @Service, @Transactional gibi @ ile başlayan her şey bir annotationSınıfa, metoda ya da alana @ ile eklenen bir not. Tek başına kod çalıştırmaz; derleyici ya da Spring gibi bir çerçeve onu okuyup bir şey yapar.@Retention notun ne zamana kadar yaşadığını (SOURCE, CLASS, RUNTIME), @Target nerelere yapıştırılabileceğini belirler.Sözlükte gör →’dır. Sınıfa, metoda ya da alana eklenen bir bilgidir; tek başına hiçbir kod çalıştırmaz.

Onu kimin okuduğu, ne zaman işe yaradığını belirler:

  • Derleyici okur: @Override yanlış yazılmış bir metodu derlerken yakalar.
  • Bir çerçeve okur: Spring, program açılırken @Service ve @Transactional notlarını okur ve buna göre davranır.
Kafam karıştı, daha basit anlat

Annotation bir etikettir. Etiketi yapıştırmak bir şey yapmaz; etiketi okuyup ona göre davranan biri gerekir. Java’da bu okuyan kişi derleyici ya da Spring gibi bir çerçevedir.

Hızlı kontrolBaşlangıç

Bir metodun üstüne kendi yazdığın `@Log` annotation'ını ekledin ama hiçbir şey olmadı. En olası sebep nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Reflection: kodun kendine bakması

reflectionProgramın çalışırken kendi sınıflarını, metotlarını, alanlarını ve notlarını incelemesi; nesne kurup metot çağırabilmesi.Spring, JPA ve JUnit gibi çerçeveler senin sınıflarını önceden bilmeden bu yolla bulur ve çalıştırır. Derleyici kontrollerini atladığı için iş kodunda seyrek kullanılır.Sözlükte gör →, programın çalışırken kendi sınıflarına bakabilmesidir: hangi metotları var, hangi notlar yapıştırılmış, kurucusu ne istiyor? Hatta bir nesne kurup bir metodu adıyla çağırabilir.

Bir sınıfa içeriden bakmak
Class<?> tip = OrderService.class;
for (Method metot : tip.getDeclaredMethods()) {
boolean islemli = metot.isAnnotationPresent(Transactional.class);
System.out.println(metot.getName() + " → işlemli mi: " + islemli);
}
Object nesne = tip.getDeclaredConstructor().newInstance(); // new yazmadan nesne

Spring de tam olarak bunu yapar: sınıfları bulur, notlarına bakar, nesnelerini kurar ve ihtiyaç duydukları parçaları verir.

Kafam karıştı, daha basit anlat

Reflection, bir sınıfa neleri olduğunu sorabilmektir. Sınıf da metotlarını ve üstündeki notları söyler. Spring bu cevaplara bakıp ne yapacağına karar verir.

Hızlı kontrolBaşlangıç

Reflection nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Spring, üzerinde `@Service` olan bir sınıfın nesnesini nasıl oluşturur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Satır satır: kendi küçük Spring’imiz

Kendi notumuzu yazalım ve onu okuyan küçük bir okuyucu kuralım. Önce bir tahmin:

Bir `@Denetle` annotation'ı yazdın ama başına `@Retention` eklemedin. Program çalışırken `isAnnotationPresent(Denetle.class)` ne döner? Cevabı göster

false. Varsayılan saklama süresi CLASS’tır: not derlenmiş dosyaya yazılır ama çalışma anında reflection’a gösterilmez. Çalışırken okumak için @Retention(RetentionPolicy.RUNTIME) gerekir.

Notu okuyan, çağrıyı yapan

MiniOkuyucu.java
şu an çalışan satır@Retention(RetentionPolicy.RUNTIME)
2@Target(ElementType.METHOD)
3@interface Denetle {}
4
5for (Method m : servis.getClass().getDeclaredMethods()) {
6 if (m.isAnnotationPresent(Denetle.class)) {
7 System.out.println("denetim: " + m.getName());
8 m.invoke(servis);
9 }
10}

Debug

Adım 1/5

not RUNTIME: not çalışma anında da okunabilsin. Bu satır olmasa aşağıdaki kontrol hep false olurdu.

Java 21UTF-8LF1:1

Sol/sağ ok tuşlarıyla da gezebilirsin.

Notu kim, ne zaman görür?

Tohum 170566

    Oynat ya da adımla: her adımda bir metot incelenir.

    Hız
    Adım 0

    Şu an ne oldu?

    Retention yok (varsayılan: CLASS) · getDeclaredMethods()

    Okuyucu @Denetle notlu metotları bulup çağıracak. İki metotta not var.

    Görevler0/3

    • Not var ama okuyucu hiçbir şey görmesinaçık

      İpucu

      Varsayılan ayarlar yeter.

    • Notlu private metodu hiç listelemeaçık

      İpucu

      Yalnızca public metotları veren yöntem.

    • İki notlu metodu da çağıraçık

      İpucu

      Saklama süresi, arama yöntemi ve erişim birlikte.

    Olay günlüğü (0)

    Henüz olay yok. Oynat veya adımla.

    1. Varsayılanla oynat. @Retention yok: iki metodun da notu var, ama okuyucu hiçbirini görmedi.
    2. “RUNTIME” seç. odemeAl çağrıldı; private iadeYap bulundu ama çağrılamadı.
    3. “getMethods()” seç. private metot hiç listelenmedi; Object’ten gelen metotlar listelendi.
    4. “getDeclaredMethods()“e dön ve “setAccessible(true)“yu aç. İki notlu metot da çağrıldı.
    Hızlı kontrolOrta

    Program ne yazdırır?

    Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
    Oku.java
    1@Target(ElementType.METHOD)
    2@interface Denetle {}
    3
    4class Servis {
    5 @Denetle
    6 void ode() {}
    7}
    8
    9Method m = Servis.class.getDeclaredMethod("ode");
    10System.out.println(m.isAnnotationPresent(Denetle.class));
    Java 21UTF-8LF

    Spring bunu nasıl kullanır?

    Spring başlarken belirttiğin paketleri tarar ve @Component, @Service, @Repository notlu sınıfları bulur. Sonra reflection ile nesnelerini kurar ve kurucularının istediği parçaları verir.

    @Transactional gibi notlar için bir adım daha atar: nesnenin önüne bir proxySpring'in bean'in yerine koyduğu sarmalayıcı nesne. `@Transactional` gibi anotasyonlar burada çalışır — çağrı proxy'den geçmezse hiçbir şey olmaz.Sözlükte gör → koyar. Her çağrı önce proxy’den geçer; proxy notu hatırlar, işlemi açar, metodu çağırır ve işlemi kapatır.

    Kafam karıştı, daha basit anlat

    Spring açılırken bütün rafları dolaşır, notlu kutuları bulur ve kurar. Bazı notlar için kutunun önüne bir görevli koyar: çağrı önce ona gelir, o da notun istediğini yapar.

    Hızlı kontrolOrta

    `@Transactional` notu, metodun etrafında işlemi nasıl açıp kapatır?

    Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

    Bir bankada kendi notunu yazmanın en güzel örneği hassas verileri gizlemektir: T.C. kimlik numarası ve IBAN gibi alanlar işaretlenir, log’a yazılırken otomatik maskelenir.

    Derinleş · @Sensitive: log'da hassas alanları maskelemek 4 dosya · ~49 satır · ilk okumada atlayabilirsin
    Proje dosyaları

    src/main/java/com/bank/privacy/ Sensitive.java Kendi notumuz: çalışma anında okunabilir, yalnızca alanlara yapıştırılır.

    src/main/java/com/bank/privacy/Sensitive.java
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Sensitive {
    }

    src/main/java/com/bank/customer/ Customer.java Müşteri: hassas alanlar işaretli.

    src/main/java/com/bank/customer/Customer.java
    public class Customer {
    private final String name;
    @Sensitive
    private final String nationalId;
    @Sensitive
    private final String iban;
    public Customer(String name, String nationalId, String iban) {
    this.name = name;
    this.nationalId = nationalId;
    this.iban = iban;
    }
    }

    src/main/java/com/bank/privacy/ SafeLog.java Okuyucu: reflection ile alanları gezer, işaretli olanları maskeler.

    src/main/java/com/bank/privacy/SafeLog.java
    public final class SafeLog {
    private SafeLog() {
    }
    public static String describe(Object target) throws IllegalAccessException {
    StringJoiner out = new StringJoiner(", ", target.getClass().getSimpleName() + "[", "]");
    for (Field field : target.getClass().getDeclaredFields()) {
    field.setAccessible(true);
    String value = String.valueOf(field.get(target));
    String shown = field.isAnnotationPresent(Sensitive.class) ? mask(value) : value;
    out.add(field.getName() + "=" + shown);
    }
    return out.toString();
    }
    // Keep only the last four characters visible.
    static String mask(String value) {
    if (value.length() <= 4) {
    return "****";
    }
    return "*".repeat(value.length() - 4) + value.substring(value.length() - 4);
    }
    }

    src/main/java/com/bank/ Main.java Çıktı yorumlarda. Alan sırası JVM'e göre değişebilir.

    src/main/java/com/bank/Main.java
    public class Main {
    public static void main(String[] args) throws Exception {
    Customer customer = new Customer("Ayşe", "12345678901", "TR000001");
    System.out.println(SafeLog.describe(customer));
    // Customer[name=Ayşe, nationalId=*******8901, iban=****0001]
    }
    }

    Tuzaklar

    @Retention unutmak. Varsayılan CLASS olduğu için notun çalışma anında görünmez; okuyucu hiçbir şey bulamaz ve hata da vermez.

    Notun kimin tarafından okunduğunu bilmemek. @Transactional bir proxy üzerinden çalışır; sınıfın kendi içinden yapılan çağrıda ya da private bir metotta etkisi olmaz.

    Reflection’ı her yerde kullanmak. Derleyicinin kontrollerini atlar, private alanlara uzanabilir ve normal çağrıdan yavaştır. Çerçeve yazarken işe yarar; günlük iş kodunda genellikle gereksizdir.

    Hızlı kontrolOrta

    Log'da hassas alanları maskeleyen kod hiçbir alanı maskelemiyor; T.C. kimlik numaraları açıkça yazılıyor. Hatanın kaynağı hangi satır?

    Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

    Hatalı satıra dokun, sonra kontrol et.

    Sensitive.java
    Java 21UTF-8LF

    Kendini sına

    Şimşek turu1/4

    Bir annotation tek başına kod çalıştırır.

    Soru 1/3Orta

    Her annotation'ı onu kimin okuduğuna göre ayır.

    Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

    Sınıflandırılmamış

    Derleyici

    Kod derlenirken okunur ve kontrol edilir.

      Çalışma anında bir çerçeve

      Program çalışırken Spring, JPA ya da JUnit okur.

        Aklında kalacak üç şey

        1. 1 Annotation yalnızca bir nottur; onu okuyup bir şey yapan bir derleyici, bir araç ya da Spring gibi bir çerçeve olmadıkça hiçbir etkisi yoktur.
        2. 2 Reflection, programın çalışırken kendi sınıflarını, metotlarını ve notlarını incelemesi, nesne kurup metot çağırmasıdır.
        3. 3 Kendi annotation'ını çalışırken okumak istiyorsan @Retention(RetentionPolicy.RUNTIME) yazarsın; yoksa not çalışma anında görünmez.
        Sonraki kapı Bir metot bazen eli boş döner. Bunu null yerine tipin kendisine nasıl yazarsın? Optional'ı Doğru Kullanmak — Yokluğu Tipe Yazmak · 8 dk

        5 kart sonraki derste seni bekliyor

        0/3 kart bu dersten toplandı