Spring Boot - Performance Tracker Annotation Entegrasyonu

Methodlarınızın hızını takip edin, haberdar olun

Ulaş Müezzinoğlu
6 min readOct 16, 2022

Herkese selamlar, bu makale de Java / Spring Boot ekosistemi içerisinde javanın biz geliştiricilere sunduğu en iyi yanlarından birisi olan Aspect Oriented Programming ve Reflection ve Polymorphism ünitelerini temel yapı taşı olarak kullanarak bir Performance Tracker Aspect ‘ i hazırlayacağız.

İyi de ne yapacağız ? kısaca şunu yapacağız, bir service methodumuzun çalışma süresini her istekte takip edip, bizim belirlediğimiz ya da default Milisaniyeden daha uzun sürdüğünde kod tarafından kendimizi bilgilendiriceğiz. Bunu sağlayabilmemiz gerçekten çok önemli. Bir kod Development ortamında istenildiği gibi çalışıyor olabilir, bir zamanlar çok hızlı çalışıyor olabilir veya başka değişken durumlarda farklı tepkiler verebilir. İşte bu noktada bu yavaşlama durumu yaşandığı anda, kullanıcı feedback ‘i almaya ya da kendiniz farketmenize gerek kalmadan direkt olarak Backend tarafından uyarılacaksınız.

Önemli Not : Bu makalede yukarıda da belirtildiği üzere sıklıkla ileri düzey programlama ünitelerinden konular işlenecektir. Bu makale, okuyucunun Aspect Oriented Programming, Reflection ve Polymorphism temeli olduğunu varsayılarak işlenecek. Bu makalede bu konuların izahı yer almıyor.

Makalenin İçeriği :

Örnek Service Kodumuzun Hazırlanması

Öncelikle Backend Projemiz içinde bir service methodu hazırlayalım, bu method bir endpoint aracılığı ile çalışacak, veritabanına gidip bazı kayıtları alıp, kullanıcısına geri response olarak döndürecek.

Yukarıda da görüldüğü üzere basit bir şekilde veritabanında Get işlemini yapan bir method ürettik. İşte tam bu methodu izlemek istiyorum, ve bu method için 100 MS’in altına düşmesini istemiyorum. eğer düşerse haberdar olmak istiyorum ki optimize edebileyim.

Custom Annotation Yapılandırması

Bu takip işlemini her ne kadar Aspect üzerinden yürütecek de olsam, Bu methodu izleyebilmek için bu methodu İmzalamam gerekiyor. Peki nasıl ? Hemen bir tane PerformanceTracker adında bir Annotation oluşturuyorum.

Burada eğer annotation method’a uygulanırken, bir limit time belirlenmez ise default olarak 1000 MS varsayılmasını istedim.

Ardından artık oluşturduğum Annotation ‘ ı method a uygulayabilirim.

AOP Konfigürasyonu

Artık Methodu takip edip, çalışma MS ini takip etmeden önce projenin Aspect yapılandırmasını sağlamam gerekiyor.

yukarıda AOP için gerekli kütüphaneyi Maven aracılığı ile projeme dahil ettim.

Hemen Ardından AOPConfig.java dosyamı yapılandırıp AOP yapısını Enable hale getiriyorum.

Performance Tracker Aspect Service Hazırlanması

Bu section Bütün makalenin en önemli noktası çünkü Hem Reflection ‘ ı Hem Aspect Yapısını hem de Öngörülemeyen durumlarda developer a Bu durumu Notify edecek service lerin hazırlanacağı kısım burası olacak.

Görüldüğü Üzere Uzun bir kod satırı bizi karşıladı, Ama endişe edecek hiçbir şey yok, burada ki her bir satır kodu tek tek inceleyeceğiz, anlayacağız.

Aslında Her şey track isimli method çevresinde gelişiyor.

Öncelikle allServicePointCut isimli PointCut da servislerimin olduğu paketi işaret ediyorum. bu sayede track methodu bu PointCut içine dahil olan tüm servislerde ve methodlarda izleme yapacak, ve içerisinde ki kodu yürütecek.

Daha sonra @Around ile service methodumun hem başlangıcında, hem de bitişinde çalışacağını belirtiyorum. Çünkü burada ki amaç , çalışmasından, bitene kadar geçen süreyi hesaplamaya ve karşılaştırmaya dayanıyor.

Artık Service methodlarım @Around seçeneği ile izlenir hale geldiğine göre öncelikle methodName adlı değişkene ProceedingJoinPoint sayesinde şu an da çalışan methodun adını aldım . (getLanguage)

Hemen ardından Args adlı değişkene o methodun imzasında ki parametreleri aldım. Burası çok önemli , Çünkü Method adlı reflection objesine erişebilmem için Hem method adına, hem de imzasında ki parametrelere ihtiyacım var. çünkü bir method overloading yapılmış olabilir. Bu durum ile nokta atışı Method objesi alabiliriz.

aynı şekilde method parametresiz de olabilir, bu yüzden lambda condition kullanarak Method objeme değeri conditional şekilde atadım.

Sistem milisaniyesini alarak, start ve end değişkenlerine atadım, dikkat edileceği üzere, ikisi arasında service methodumu proceed ettirdim. ki end değişkenine gelene kadar method çalışıp işini bitirmiş olsun,

Artık elimde Method objesi ve kaç saniye süresince çalıştığı bilgisi olduğuna göre esas kontrole başlayabilirim.

method.isAnnotationPresent(PerformanceTracker.class)

ile method, PerformanceTracker annotation ı tarafından imzalanmış mı onu öğrendim. eğer imzalanmamışsa , herhangi bir MS kontrolü yapmana gerek yok, ben o methodu izlemiyorum düşüncesindeyizdir. Ama yok imzalanmışsa, devamında şu kod takip eder,

Buradan çıkaralıcak sonuç şu şekildedir : Eğer method, takip ettiğim bir method ise bak bakalım çalışma süresi, Annotation da belirtilmiş süreden fazla mı ? eğer fazla ise orada bir notify işlemi yapıyoruz. Eğer değilse her şey yolundadır, kod akmaya devam edebilir.

Notify Service Hazırlanması

Artık sonlara doğru geldiğimizde sadece Anormal durumun, Developer a notify edilmesi kısmı kaldı. Ama burada zengin bir tasarım yapmak istediğim için, Polymorphism Standartında yapmak istiyorum, Öyle if else ile kodu spagetti hale getirmek istemiyorum.

Öncelikle PerformanceNotifyService oluşturup içinde notifyLatedMethod imzasını geçiyorum.

Ardından Tam 4 tane farklı bildirme seçeneği tanımlıyorum

  • Database e bildir
  • Sms aracılığı ile bildir
  • Email Aracılığı ile bildir
  • Elastic Search e bildir

Bunun için 4 tane Service oluşturup, hepsini PerformanceNotifyService den implement ederek Polymorphism sağlıyorum.

Örnek olması için sadece DatabaseNotifyServiceImpl Service sınıfını dolduracağım.

Yukarıda ki @Primary Annotation ına dikkat edin. Aynı imzayı taşıyan 4 farklı Service olduğundan, Autowired esnasında hangi referansı getireceğini @Primary ile belirliyorum. Eğer yarın öbür gün, Email ya da Elastic Search e bildirmesini isteyecek olursam, @Primary annotation ‘ını gidip o service e taşımam yeterli olacaktır.

Şimdi Test Etme Zamanı !

Postman aracılığı ile o service methodumu tetikleyerek methodun gecikip, gecikmeyeceğini test edelim. ve gecikirse ne olacağına bakalım.

Görüldüğü üzere 20 Milisaniye de başarılı şekilde yanıt alabildim. ben eğer 500 Milisaniye üzerine çıkarsa bana haber ver demiştim.

Thread.sleep(3000);

kod satırı ile methodu 3000 Milisaniye uyutacağım, ve method gecikicek, tepkiye bakalım.

Method artık 3000 ms daha geç çalışıyor, hemen veritabanımı kontrol edeceğim.

Harika ! artık methodlarım beklenenden daha geç cevap verecek olursa, istediğim şekilde haberdar olup, hangi method ? kaç saniyede çalışmış ? normalde ne kadar da çalışması gerekiyor ? bilgileriyle beraber persist olarak depoladım. Artık sorunu anında görüp, Optimizasyon sağlayabilirim.

Ayrıca bunu onlarca, hatta yüzlerce methoda birden tanımlayıp, her birisi ayrı MS Limit koyabilirim.

Önemli Notlar ve Dikkat edilmesi gereken hususlar

Şimdi bazı okurlarımızın kafasında “ YAHU NEDEN ?” sorusu oluşmuş olabilir. Neden method içine girip 2 3 satırda bunu yapmadık da bir ton kod yazdık diyebilirsiniz. Bunun En temel sebebi ve sorunuzun cevabı S.O.L.I.D prensibleridir. Tek Sorumluluk ilkesi gereğince, getLanguage methodu sadece ama sadece get Language işlemi yapmak ile yükümlüdür. başka bir yaparsa SOLID ‘ın S ilkesine aykırı olur. Bu yüzden bunu aspect e taşıdık. ayrıca en merkezi noktada olup, istediğimiz tüm methodlar için geçerli olup, kod tekrarının da önüne geçtik.

Performance Tracker Aspect Konusunu elimden geldiğince izah etmeye çalıştım. Umarım aradığınızı bulmuşsunuzdur.

Destek olmak için Github Adresimi ve Linkedin Profilimi ziyaret edebilirsiniz.

Şimdiden Teşekkürler, iyi çalışmalar.

Sign up to discover human stories that deepen your understanding of the world.

--

--

No responses yet

Write a response