Soru geçmişi:
Proxy nesneleri ve Proxy deseni Java'da, gerçek bir nesneye erişimi kontrol edebilen, davranışını değiştirebilen veya kesişen işlevleri (güvenlik, günlüğe kaydetme, metrikler) enjekte edebilen yer tutucu nesneleri oluşturmak için ortaya çıktı. Java 1.3'ten itibaren, java.lang.reflect paketinde standart dinamik proxy'ler için destek eklendi ve sonrasında CGLIB ve ByteBuddy gibi popüler kütüphaneler geliştirildi.
Problem:
Mevcut bir sınıfın mantığını doğrudan değiştirmek her zaman mümkün veya pratik değildir. Sıklıkla, mevcut nesnenin kaynak kodunu değiştirmeden şeffaf bir şekilde davranış eklemek (örneğin, günlüğe kaydetme, önbellekleme, işlemler) gerekmektedir. Bu, standart kalıtım araçları ile mümkün değildir.
Çözüm:
Proxy nesneleri, statik (manuel alt sınıflama ile) veya dinamik (yansıma veya bayt kodu mekanizması ile) olarak uygulanabilir. Dinamik proxy, gerekli arayüzü gerçekleştiren nesneleri anlık olarak oluşturmaya olanak tanır ve çağrıları gerçek nesneye invoke() metodu içinde devreder, bu da üçüncü taraf davranışlarını enjekte etmek için esneklik sağlar.
Kod örneği:
import java.lang.reflect.*; interface Service { void doWork(); } class RealService implements Service { public void doWork() { System.out.println("Çalışmayı yapıyorum!"); } } class LoggingInvocationHandler implements InvocationHandler { private final Object target; public LoggingInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Çağrılıyor: " + method.getName()); return method.invoke(target, args); } } Service real = new RealService(); Service proxy = (Service) Proxy.newProxyInstance( real.getClass().getClassLoader(), new Class[] {Service.class}, new LoggingInvocationHandler(real)); proxy.doWork(); // Günlük kaydı çağrılıyor
Anahtar özellikler:
Java'daki standart dinamik Proxy, arayüz uygulamayan sınıflar ile çalışabilir mi?
Hayır. Java'daki standart Proxy yalnızca arayüzlerle çalışır. Arayüzü olmayan sınıflar için (örneğin, sıradan bir sınıfı proxy'lemek istiyorsanız) üçüncü taraf araçlara (örneğin, CGLIB, ByteBuddy) ihtiyaç vardır.
Özel yöntemleri olan bir arayüz için proxy oluşturulabilir mi?
Hayır. Java'daki arayüzler, proxy'lenmesi gereken özel yöntemleri içeremez. Dinamik proxy, arayüzün genel yöntemlerini uygular. Java 9'dan itibaren özel varsayılan yöntemler eklendi, ancak bunlar proxy üzerinden erişilemez.
InvocationHandler ile MethodInterceptor (CGLIB) arasındaki fark nedir?
InvocationHandler, dinamik proxy'ler için kullanılan standart JDK arayüzüdür. Arayüzün yöntem çağrılarını kabul eder. MethodInterceptor, dinamik kalıtım yoluyla herhangi bir sınıfta yöntem çağrılarını yakalayan CGLIB arayüzüdür. Uygulama ve seviye açısından fark: JDK yalnızca arayüzlerle çalışır, CGLIB ise herhangi bir sınıfla çalışır.
Mühendis, tüm hizmetlerdeki her yöntemde günlüğe alma kodunu manuel olarak tekrarlar. Yeni yöntemler eklendiğinde mantığı sürekli tekrarlar, genellikle gerekli çağrıları eklemeyi unutur.
Artıları:
Eksileri:
Projeye, dinamik proxy üzerinden AOP entegre edilmiştir: günlüğe alma ve işlem kontrolü merkezi olarak gerçekleştirilen yer tutucu sarfiyatları ile gerçekleştirilir.
Artıları:
Eksileri: