{"id":35526,"date":"2025-11-30T19:01:06","date_gmt":"2025-11-30T16:01:06","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/"},"modified":"2025-11-30T19:01:06","modified_gmt":"2025-11-30T16:01:06","slug":"java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/","title":{"rendered":"Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?"},"content":{"rendered":"<p><body><\/p>\n<p>Uygulamalar\u0131n\u0131z\u0131 daha mod\u00fcler ve esnek hale getirmek ister misiniz? Java SPI mekanizmas\u0131 ile kendi basit eklenti mimarinizi ad\u0131m ad\u0131m nas\u0131l kuraca\u011f\u0131n\u0131z\u0131 ke\u015ffedin ve kodunuzu gelece\u011fe haz\u0131rlay\u0131n.<\/p>\n<p>G\u00fcn\u00fcm\u00fcz yaz\u0131l\u0131m d\u00fcnyas\u0131nda, uygulamalar\u0131n s\u00fcrekli geli\u015fen ihtiya\u00e7lara ayak uydurmas\u0131 ve kolayca geni\u015fletilebilir olmas\u0131 hayati \u00f6nem ta\u015f\u0131r. Monolitik, s\u0131k\u0131ca ba\u011fl\u0131 sistemler, yeni \u00f6zellikler ekleme, mevcut i\u015flevleri de\u011fi\u015ftirme veya \u00fc\u00e7\u00fcnc\u00fc taraf entegrasyonlar\u0131 yapma s\u00fcre\u00e7lerinde ciddi zorluklar yaratabilir. \u0130\u015fte bu noktada eklenti (plugin) mimarisi devreye girer. Peki, tam olarak neden bir eklenti mimarisine ihtiya\u00e7 duyar\u0131z?<\/p>\n<p>Her \u015feyden \u00f6nce, <strong>mod\u00fclerlik ve sorumluluk ayr\u0131l\u0131\u011f\u0131<\/strong> prensiplerini g\u00fc\u00e7lendiririz. Bir eklenti mimarisi sayesinde, uygulaman\u0131z\u0131n \u00e7ekirdek mant\u0131\u011f\u0131n\u0131 (core logic) farkl\u0131 i\u015flevlerden ay\u0131rabilirsiniz. \u00d6rne\u011fin, bir medya oynat\u0131c\u0131n\u0131n temel oynatma i\u015flevselli\u011fi \u00e7ekirdek uygulamada kal\u0131rken, farkl\u0131 ses\/video formatlar\u0131n\u0131 i\u015fleme yetene\u011fi ayr\u0131 eklentilerle sa\u011flanabilir. Bu durum, kod taban\u0131n\u0131n daha anla\u015f\u0131l\u0131r olmas\u0131n\u0131, her mod\u00fcl\u00fcn kendi sorumlulu\u011funu ta\u015f\u0131mas\u0131n\u0131 ve b\u00f6ylece bak\u0131m\u0131n\u0131n kolayla\u015fmas\u0131n\u0131 sa\u011flar.<\/p>\n<p>Ayr\u0131ca, <strong>uygulama esnekli\u011fi ve geni\u015fletilebilirlik<\/strong> en b\u00fcy\u00fck faydalar\u0131ndan biridir. Bir eklenti mimarisi, uygulaman\u0131z\u0131n temel kodunu de\u011fi\u015ftirmeye gerek kalmadan yeni \u00f6zellikler eklemenize olanak tan\u0131r. Diyelim ki bir raporlama arac\u0131n\u0131z var ve ba\u015flang\u0131\u00e7ta sadece PDF ve Excel format\u0131nda \u00e7\u0131kt\u0131 veriyor. Gelecekte HTML veya CSV formatlar\u0131n\u0131 da desteklemek isterseniz, eklenti mimarisi sayesinde sadece ilgili format i\u00e7in yeni bir eklenti yazman\u0131z yeterli olur. Ana uygulaman\u0131z, bu yeni eklentiyi otomatik olarak alg\u0131lar ve kullan\u0131ma sunar. Bu, uygulaman\u0131z\u0131n \u00f6mr\u00fcn\u00fc uzat\u0131r ve de\u011fi\u015fen gereksinimlere daha h\u0131zl\u0131 adapte olmas\u0131n\u0131 sa\u011flar.<\/p>\n<p>Bir di\u011fer \u00f6nemli avantaj ise <strong>\u00fc\u00e7\u00fcnc\u00fc taraf entegrasyonlar\u0131 ve topluluk deste\u011fi<\/strong> potansiyelidir. A\u00e7\u0131k kaynak projelerde veya geni\u015f bir kullan\u0131c\u0131 taban\u0131na sahip \u00fcr\u00fcnlerde, geli\u015ftiricilerin kendi eklentilerini yazarak uygulamaya katk\u0131da bulunmalar\u0131na olanak tan\u0131yan bir yap\u0131 olu\u015fturmak paha bi\u00e7ilmezdir. Bu, uygulaman\u0131z\u0131n ekosistemini zenginle\u015ftirir ve yenilik\u00e7i \u00e7\u00f6z\u00fcmlerin ortaya \u00e7\u0131kmas\u0131n\u0131 te\u015fvik eder. \u00d6te yandan, ticari uygulamalar i\u00e7in de esneklik sunar; m\u00fc\u015fterilerinizin veya i\u015f ortaklar\u0131n\u0131z\u0131n kendi \u00f6zel ihtiya\u00e7lar\u0131na g\u00f6re eklentiler geli\u015ftirmelerine izin verebilirsiniz.<\/p>\n<p>Son olarak, <strong>bak\u0131m kolayl\u0131\u011f\u0131 ve hata izolasyonu<\/strong> da \u00f6nemli bir fakt\u00f6rd\u00fcr. E\u011fer bir eklentide bir hata olu\u015fursa, bu hata genellikle yaln\u0131zca o eklentiyi etkiler ve ana uygulaman\u0131n veya di\u011fer eklentilerin \u00e7al\u0131\u015fmas\u0131n\u0131 bozmaz. Bu durum, hatalar\u0131n te\u015fhis edilmesini ve d\u00fczeltilmesini kolayla\u015ft\u0131r\u0131r. Ayr\u0131ca, belirli bir \u00f6zelli\u011fi de\u011fi\u015ftirmek veya y\u00fckseltmek istedi\u011finizde, sadece ilgili eklenti \u00fczerinde \u00e7al\u0131\u015fman\u0131z yeterlidir; t\u00fcm uygulamay\u0131 yeniden derlemenize veya da\u011f\u0131tman\u0131za gerek kalmaz.<\/p>\n<p>\u00d6rne\u011fin, bir bankac\u0131l\u0131k uygulamas\u0131n\u0131 d\u00fc\u015f\u00fcn\u00fcn. Farkl\u0131 \u00fclkelerdeki mevzuat gereksinimleri farkl\u0131 olabilir. Her \u00fclke i\u00e7in ayr\u0131 bir \u00e7ekirdek uygulama geli\u015ftirmek yerine, \u00e7ekirdek i\u015flevleri sabit tutup \u00fclkeye \u00f6zg\u00fc kurallar\u0131 ve entegrasyonlar\u0131 eklentiler arac\u0131l\u0131\u011f\u0131yla sa\u011flamak, hem geli\u015ftirme maliyetlerini d\u00fc\u015f\u00fcr\u00fcr hem de uygulaman\u0131n uluslararas\u0131 alanda geni\u015flemesini kolayla\u015ft\u0131r\u0131r. Bu \u00f6rnekte g\u00f6rd\u00fc\u011f\u00fcn\u00fcz gibi, eklenti mimarileri sadece teknik bir tercih olmaktan \u00f6te, stratejik bir i\u015f karar\u0131 haline de gelebilir. Bu faydalar\u0131 g\u00f6z \u00f6n\u00fcnde bulundurdu\u011fumuzda, Java SPI gibi basit ama g\u00fc\u00e7l\u00fc mekanizmalarla kendi eklenti mimarimizi in\u015fa etmek olduk\u00e7a cazip bir se\u00e7enek olarak \u00f6ne \u00e7\u0131kmaktad\u0131r.<\/p>\n<h2>Java SPI Mekanizmas\u0131 Nedir ve Nas\u0131l \u00c7al\u0131\u015f\u0131r?<\/h2>\n<p>Java ekosisteminde eklenti mimarisi denildi\u011finde akla gelen ilk yerle\u015fik mekanizmalardan biri, <strong>Service Provider Interface (SPI)<\/strong>&#8216;d\u0131r. Java SPI, Java platformunun kendisinde de yayg\u0131n olarak kullan\u0131lan, servis sa\u011flay\u0131c\u0131lar\u0131n\u0131 dinamik olarak ke\u015ffetmek ve y\u00fcklemek i\u00e7in tasarlanm\u0131\u015f basit ama etkili bir y\u00f6ntemdir. Peki, bu mekanizma tam olarak nedir ve arka planda nas\u0131l bir \u00e7al\u0131\u015fma prensibine sahiptir?<\/p>\n<p>Java SPI&#8217;nin temel amac\u0131, bir uygulaman\u0131n (veya bir API&#8217;nin) bilinen bir aray\u00fcz\u00fc veya soyut s\u0131n\u0131f\u0131 uygulayan somut implementasyonlar\u0131 (servis sa\u011flay\u0131c\u0131lar\u0131) \u00e7al\u0131\u015fma zaman\u0131nda bulabilmesini sa\u011flamakt\u0131r. Yani, uygulaman\u0131z belirli bir &#8220;servis&#8221;e ihtiya\u00e7 duydu\u011funda, bu servisi sa\u011flayan t\u00fcm implementasyonlar\u0131 kendisi otomatik olarak ke\u015ffedebilir. Bu sayede, uygulaman\u0131z\u0131n ana koduna yeni bir servis sa\u011flay\u0131c\u0131 eklemek i\u00e7in kaynak kodda hi\u00e7bir de\u011fi\u015fiklik yapman\u0131za gerek kalmaz. Bu, tam da bir eklenti mimarisinden bekledi\u011fimiz esnekli\u011fi ve geni\u015fletilebilirli\u011fi sunar.<\/p>\n<p>Java SPI&#8217;nin \u00e7al\u0131\u015fma prensibi olduk\u00e7a basittir ve ana bile\u015feni <code>java.util.ServiceLoader<\/code> s\u0131n\u0131f\u0131d\u0131r. Bu s\u0131n\u0131f, belirli bir servis aray\u00fcz\u00fc i\u00e7in mevcut t\u00fcm servis sa\u011flay\u0131c\u0131lar\u0131n\u0131 bulmaktan ve y\u00fcklemekten sorumludur. Servis sa\u011flay\u0131c\u0131lar\u0131 bulabilmek i\u00e7in <code>ServiceLoader<\/code>, \u00e7al\u0131\u015fma zaman\u0131nda (runtime) classpath \u00fczerinde \u00f6zel bir dizini tarar: <code>META-INF\/services\/<\/code>. Bu dizin alt\u0131nda, servis aray\u00fcz\u00fcn\u00fcn tam nitelikli ad\u0131n\u0131 ta\u015f\u0131yan dosyalar bulunur. \u00d6rne\u011fin, e\u011fer servis aray\u00fcz\u00fcn\u00fcz <code>com.example.MyService<\/code> ise, <code>META-INF\/services\/com.example.MyService<\/code> ad\u0131nda bir dosya arayacakt\u0131r.<\/p>\n<p>Bu dosyan\u0131n i\u00e7eri\u011fi ise, <code>com.example.MyService<\/code> aray\u00fcz\u00fcn\u00fc uygulayan somut s\u0131n\u0131flar\u0131n tam nitelikli adlar\u0131n\u0131 i\u00e7erir. Her sat\u0131rda bir s\u0131n\u0131f ad\u0131 olacak \u015fekilde listelenirler. <code>ServiceLoader<\/code> bu dosyadaki s\u0131n\u0131f adlar\u0131n\u0131 okur, bu s\u0131n\u0131flar\u0131 y\u00fckler ve her biri i\u00e7in birer \u00f6rnek (instance) olu\u015fturur. B\u00f6ylece, uygulaman\u0131z bu servis sa\u011flay\u0131c\u0131lar\u0131 kullan\u0131ma haz\u0131r bir \u015fekilde elde eder. Bu i\u015flem genellikle tembel (lazy) y\u00fckleme mekanizmas\u0131yla \u00e7al\u0131\u015f\u0131r; yani, sa\u011flay\u0131c\u0131lar sadece ihtiya\u00e7 duyuldu\u011funda y\u00fcklenir ve \u00f6rneklendirilir.<\/p>\n<div class=\"expert-tip\">\n        Uzman \u0130pucu: Java SPI mekanizmas\u0131, Java&#8217;n\u0131n kendi JDBC s\u00fcr\u00fcc\u00fcleri, JAXP (Java API for XML Processing) sa\u011flay\u0131c\u0131lar\u0131 veya Common Logger sa\u011flay\u0131c\u0131lar\u0131 gibi bir\u00e7ok dahili servisinde ba\u015far\u0131yla kullan\u0131lmaktad\u0131r. Bu, mekanizman\u0131n g\u00fcvenilirli\u011fini ve pratikli\u011fini kan\u0131tlar.\n    <\/div>\n<p>Java SPI&#8217;nin ba\u015fl\u0131ca avantajlar\u0131 aras\u0131nda kullan\u0131m kolayl\u0131\u011f\u0131, Java platformunun do\u011fal bir par\u00e7as\u0131 olmas\u0131 ve d\u0131\u015f ba\u011f\u0131ml\u0131l\u0131k gerektirmemesi yer al\u0131r. Temel eklenti ihtiya\u00e7lar\u0131 i\u00e7in m\u00fckemmel bir ba\u015flang\u0131\u00e7 noktas\u0131d\u0131r. Ancak, daha karma\u015f\u0131k senaryolarda, \u00f6rne\u011fin eklentilerin ya\u015fam d\u00f6ng\u00fcs\u00fcn\u00fc y\u00f6netme, ba\u011f\u0131ml\u0131l\u0131k enjeksiyonu veya g\u00fcvenlik sandbox&#8217;lar\u0131 olu\u015fturma gibi konularda, OSGi gibi daha geli\u015fmi\u015f mod\u00fclerlik framework&#8217;lerinin sa\u011flad\u0131\u011f\u0131 yeteneklere ihtiya\u00e7 duyulabilir. Yine de, basit ve etkili bir eklenti mimarisi kurmak isteyenler i\u00e7in Java SPI olduk\u00e7a sa\u011flam ve anla\u015f\u0131l\u0131r bir temel sunar.<\/p>\n<p>\u00d6te yandan, Java SPI&#8217;nin baz\u0131 s\u0131n\u0131rl\u0131l\u0131klar\u0131 da mevcuttur. \u00d6rne\u011fin, servis sa\u011flay\u0131c\u0131lar\u0131n\u0131n y\u00fcklenme s\u0131ras\u0131 \u00fczerinde do\u011frudan bir kontrol mekanizmas\u0131 sunmaz. Ayr\u0131ca, bir servis sa\u011flay\u0131c\u0131s\u0131n\u0131n parametreli bir kurucu metoda sahip olmas\u0131 durumunda, <code>ServiceLoader<\/code> varsay\u0131lan olarak parametresiz kurucuyu arad\u0131\u011f\u0131 i\u00e7in sorun ya\u015fanabilir. Bu t\u00fcr durumlarda ek konfig\u00fcrasyon veya Fabrika (Factory) desenleri kullanmak gerekebilir. Bununla birlikte, bu s\u0131n\u0131rlamalar genellikle basit eklenti ihtiya\u00e7lar\u0131 i\u00e7in g\u00f6z ard\u0131 edilebilir veya kolayca a\u015f\u0131labilir. Dolay\u0131s\u0131yla, Java SPI, yaz\u0131l\u0131m mimarisine mod\u00fclerlik katmak isteyen her Java geli\u015ftiricisi i\u00e7in bilmesi gereken temel bir ara\u00e7t\u0131r.<\/p>\n<h2>Ad\u0131m Ad\u0131m Basit Bir Eklenti Mimarisi Olu\u015fturma: Temel Bile\u015fenler<\/h2>\n<p>\u015eimdiye kadar eklenti mimarisinin faydalar\u0131n\u0131 ve Java SPI&#8217;nin temel prensiplerini \u00f6\u011frendik. Art\u0131k s\u0131ra, bu bilgileri prati\u011fe d\u00f6kerek kendi basit eklenti mimarimizi olu\u015fturmaya geldi. Bu b\u00f6l\u00fcmde, bir eklenti sisteminin \u00fc\u00e7 ana bile\u015fenini (API, Servis Sa\u011flay\u0131c\u0131lar\u0131 ve Ana Uygulama) ad\u0131m ad\u0131m nas\u0131l geli\u015ftirece\u011fimizi kod \u00f6rnekleriyle birlikte inceleyece\u011fiz. Bu \u00f6rnekte, basit bir mesajla\u015fma servisi i\u00e7in farkl\u0131 dillerde mesaj \u00fcretebilen eklentiler geli\u015ftirece\u011fiz.<\/p>\n<h3>Ad\u0131m 1: Servis Aray\u00fcz\u00fcn\u00fc Tan\u0131mlama (API Mod\u00fcl\u00fc)<\/h3>\n<p>Eklenti mimarisindeki ilk ve en kritik ad\u0131m, servis aray\u00fcz\u00fcn\u00fc tan\u0131mlamakt\u0131r. Bu aray\u00fcz, uygulaman\u0131z\u0131n eklentilerden ne t\u00fcr bir i\u015flevsellik bekledi\u011fini belirler. Hem ana uygulama hem de t\u00fcm eklentiler bu aray\u00fcze ba\u011f\u0131ml\u0131 olacakt\u0131r. Bu nedenle, bu aray\u00fcz m\u00fcmk\u00fcn oldu\u011funca kararl\u0131 ve iyi d\u00fc\u015f\u00fcn\u00fclm\u00fc\u015f olmal\u0131d\u0131r. Genellikle bu aray\u00fcz\u00fc i\u00e7eren k\u0131sma &#8220;API Mod\u00fcl\u00fc&#8221; denir.<\/p>\n<p>Bir Maven projesi olarak <code>message-api<\/code> ad\u0131nda bir mod\u00fcl olu\u015ftural\u0131m. Bu mod\u00fcl sadece servis aray\u00fcz\u00fcn\u00fc i\u00e7erecek. Di\u011fer mod\u00fcller bu API mod\u00fcl\u00fcne ba\u011f\u0131ml\u0131l\u0131k olarak ekleyecek.<\/p>\n<p><code>message-api\/src\/main\/java\/com\/example\/api\/MessageService.java<\/code> dosyam\u0131z \u015f\u00f6yle g\u00f6r\u00fcnecek:<\/p>\n<pre><code class=\"language-java\">package com.example.api;\n\npublic interface MessageService {\n    \/**\n     * Belirli bir dile \u00f6zg\u00fc bir kar\u015f\u0131lama mesaj\u0131 d\u00f6nd\u00fcr\u00fcr.\n     * @return Kar\u015f\u0131lama mesaj\u0131.\n     *\/\n    String getGreeting();\n\n    \/**\n     * Bu servisin destekledi\u011fi dilin kodunu d\u00f6nd\u00fcr\u00fcr.\n     * \u00d6rne\u011fin: \"en\", \"tr\".\n     * @return Dil kodu.\n     *\/\n    String getLanguageCode();\n}\n<\/pre>\n<p><\/code><\/p>\n<p>Bu aray\u00fcz, her eklentinin iki metot uygulamas\u0131n\u0131 bekliyor: bir kar\u015f\u0131lama mesaj\u0131 d\u00f6nd\u00fcren <code>getGreeting()<\/code> ve eklentinin destekledi\u011fi dilin kodunu d\u00f6nd\u00fcren <code>getLanguageCode()<\/code>. Bu aray\u00fcz, eklentilerimiz i\u00e7in s\u00f6zle\u015fmemizdir. Ana uygulama, bu aray\u00fcz\u00fc kullanarak eklentilerle etkile\u015fime girecektir.<\/p>\n<h3>Ad\u0131m 2: Servis Sa\u011flay\u0131c\u0131lar\u0131 Geli\u015ftirme (Plugin Mod\u00fclleri)<\/h3>\n<p>\u015eimdi s\u0131ra, API mod\u00fcl\u00fcm\u00fczde tan\u0131mlad\u0131\u011f\u0131m\u0131z <code>MessageService<\/code> aray\u00fcz\u00fcn\u00fc uygulayan somut servis sa\u011flay\u0131c\u0131lar\u0131 olu\u015fturmaya geldi. Her bir sa\u011flay\u0131c\u0131, belirli bir dil i\u00e7in bir eklenti g\u00f6revi g\u00f6recektir. Bunlara \"Plugin Mod\u00fclleri\" diyebiliriz.<\/p>\n<p>\u0130lk olarak, \u0130ngilizce i\u00e7in bir eklenti olu\u015ftural\u0131m. <code>english-plugin<\/code> ad\u0131nda yeni bir Maven mod\u00fcl\u00fc olu\u015ftural\u0131m ve <code>message-api<\/code> mod\u00fcl\u00fcne ba\u011f\u0131ml\u0131l\u0131k olarak ekleyelim.<\/p>\n<p><code>english-plugin\/src\/main\/java\/com\/example\/plugins\/EnglishMessageService.java<\/code>:<\/p>\n<pre><code class=\"language-java\">package com.example.plugins;\n\nimport com.example.api.MessageService;\n\npublic class EnglishMessageService implements MessageService {\n    @Override\n    public String getGreeting() {\n        return \"Hello from English Plugin!\";\n    }\n\n    @Override\n    public String getLanguageCode() {\n        return \"en\";\n    }\n}\n<\/pre>\n<p><\/code><\/p>\n<p>Ard\u0131ndan, T\u00fcrk\u00e7e i\u00e7in bir eklenti olu\u015ftural\u0131m. <code>turkish-plugin<\/code> ad\u0131nda ba\u015fka bir Maven mod\u00fcl\u00fc olu\u015ftural\u0131m ve yine <code>message-api<\/code> mod\u00fcl\u00fcne ba\u011f\u0131ml\u0131l\u0131k olarak ekleyelim.<\/p>\n<p><code>turkish-plugin\/src\/main\/java\/com\/example\/plugins\/TurkishMessageService.java<\/code>:<\/p>\n<pre><code class=\"language-java\">package com.example.plugins;\n\nimport com.example.api.MessageService;\n\npublic class TurkishMessageService implements MessageService {\n    @Override\n    public String getGreeting() {\n        return \"Merhaba from Turkish Plugin!\";\n    }\n\n    @Override\n    public String getLanguageCode() {\n        return \"tr\";\n    }\n}\n<\/pre>\n<p><\/code><\/p>\n<p>En kritik ad\u0131m burada geliyor: Java SPI mekanizmas\u0131n\u0131n bu servis sa\u011flay\u0131c\u0131lar\u0131n\u0131 bulabilmesi i\u00e7in \u00f6zel bir konfig\u00fcrasyon dosyas\u0131 olu\u015fturmam\u0131z gerekiyor. Her bir plugin mod\u00fcl\u00fcn\u00fcn <code>src\/main\/resources\/META-INF\/services\/<\/code> dizini alt\u0131nda, servis aray\u00fcz\u00fcm\u00fcz\u00fcn tam nitelikli ad\u0131n\u0131 ta\u015f\u0131yan bir dosya olmal\u0131d\u0131r.<\/p>\n<p><code>english-plugin\/src\/main\/resources\/META-INF\/services\/com.example.api.MessageService<\/code> dosyas\u0131n\u0131n i\u00e7eri\u011fi:<\/p>\n<pre><code>com.example.plugins.EnglishMessageService\n<\/pre>\n<p><\/code><\/p>\n<p><code>turkish-plugin\/src\/main\/resources\/META-INF\/services\/com.example.api.MessageService<\/code> dosyas\u0131n\u0131n i\u00e7eri\u011fi:<\/p>\n<pre><code>com.example.plugins.TurkishMessageService\n<\/pre>\n<p><\/code><\/p>\n<p>Bu dosyalar, <code>ServiceLoader<\/code>'a hangi s\u0131n\u0131flar\u0131n <code>MessageService<\/code> aray\u00fcz\u00fcn\u00fc uygulad\u0131\u011f\u0131n\u0131 bildirir. Her dosya, ilgili servis sa\u011flay\u0131c\u0131s\u0131n\u0131n tam nitelikli s\u0131n\u0131f ad\u0131n\u0131 i\u00e7ermelidir. Birden fazla sa\u011flay\u0131c\u0131 varsa, her sa\u011flay\u0131c\u0131 ayr\u0131 bir sat\u0131ra yaz\u0131l\u0131r.<\/p>\n<h3>Ad\u0131m 3: Eklentileri Y\u00fckleyen ve Kullanan Uygulama (Uygulama Mod\u00fcl\u00fc)<\/h3>\n<p>Son olarak, eklentilerimizi dinamik olarak bulup y\u00fckleyecek ve kullanacak olan ana uygulamay\u0131 geli\u015ftirelim. Bu mod\u00fcle \"Uygulama Mod\u00fcl\u00fc\" diyebiliriz. <code>app<\/code> ad\u0131nda yeni bir Maven mod\u00fcl\u00fc olu\u015ftural\u0131m ve hem <code>message-api<\/code> hem de <code>english-plugin<\/code> ve <code>turkish-plugin<\/code> mod\u00fcllerine ba\u011f\u0131ml\u0131l\u0131k olarak ekleyelim. Maven'da bu ba\u011f\u0131ml\u0131l\u0131klar\u0131 eklerken, eklenti mod\u00fcllerinin <code>JAR<\/code> dosyalar\u0131n\u0131n classpath'e dahil edildi\u011finden emin olmal\u0131y\u0131z. Genellikle multi-module bir Maven projesinde bu ba\u011f\u0131ml\u0131l\u0131klar\u0131 do\u011frudan eklersiniz.<\/p>\n<p><code>app\/src\/main\/java\/com\/example\/app\/App.java<\/code> dosyam\u0131z:<\/p>\n<pre><code class=\"language-java\">package com.example.app;\n\nimport com.example.api.MessageService;\nimport java.util.ServiceLoader;\n\npublic class App {\n    public static void main(String[] args) {\n        System.out.println(\"Eklentileri y\u00fcklemeye ba\u015fl\u0131yoruz...\");\n\n        \/\/ ServiceLoader kullanarak t\u00fcm MessageService sa\u011flay\u0131c\u0131lar\u0131n\u0131 bulma\n        ServiceLoader<MessageService> serviceLoader = ServiceLoader.load(MessageService.class);\n\n        int pluginCount = 0;\n        for (MessageService service : serviceLoader) {\n            pluginCount++;\n            System.out.println(\"------------------------------------\");\n            System.out.println(\"Bulunan Eklenti: \" + service.getClass().getName());\n            System.out.println(\"Desteklenen Dil Kodu: \" + service.getLanguageCode());\n            System.out.println(\"Mesaj: \" + service.getGreeting());\n            System.out.println(\"------------------------------------\");\n        }\n\n        if (pluginCount == 0) {\n            System.out.println(\"Hi\u00e7bir MessageService eklentisi bulunamad\u0131!\");\n        } else {\n            System.out.println(pluginCount + \" adet eklenti ba\u015far\u0131yla y\u00fcklendi.\");\n        }\n\n        \/\/ Belirli bir dil i\u00e7in eklentiyi bulma \u00f6rne\u011fi\n        System.out.println(\"\\nT\u00fcrk\u00e7e eklentiyi \u00f6zel olarak ar\u0131yoruz...\");\n        MessageService turkishService = findServiceByLanguageCode(serviceLoader, \"tr\");\n        if (turkishService != null) {\n            System.out.println(\"T\u00fcrk\u00e7e Mesaj: \" + turkishService.getGreeting());\n        } else {\n            System.out.println(\"T\u00fcrk\u00e7e eklenti bulunamad\u0131.\");\n        }\n    }\n\n    private static MessageService findServiceByLanguageCode(ServiceLoader<MessageService> serviceLoader, String langCode) {\n        for (MessageService service : serviceLoader) {\n            if (service.getLanguageCode().equalsIgnoreCase(langCode)) {\n                return service;\n            }\n        }\n        return null;\n    }\n}\n<\/pre>\n<p><\/code><\/p>\n<p><code>ServiceLoader.load(MessageService.class)<\/code> \u00e7a\u011fr\u0131s\u0131, <code>MessageService<\/code> aray\u00fcz\u00fcn\u00fc uygulayan t\u00fcm servis sa\u011flay\u0131c\u0131lar\u0131n\u0131 otomatik olarak bulur ve bir <code>Iterable<\/code> d\u00f6nd\u00fcr\u00fcr. Ana uygulamam\u0131z, bu <code>Iterable<\/code> \u00fczerinde d\u00f6ng\u00fc yaparak her bir eklentiyi kullanabilir. Bu, ana uygulaman\u0131n yeni eklentiler eklendi\u011finde veya \u00e7\u0131kar\u0131ld\u0131\u011f\u0131nda kod de\u011fi\u015ftirmeden \u00e7al\u0131\u015fmaya devam edebilece\u011fi anlam\u0131na gelir.<\/p>\n<p>Bu ad\u0131mlar\u0131 takip ederek, Java SPI mekanizmas\u0131n\u0131 kullanarak basit ama i\u015flevsel bir eklenti mimarisi olu\u015fturmu\u015f olduk. Art\u0131k ana uygulaman\u0131z\u0131 derleyip \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131n\u0131zda, <code>english-plugin<\/code> ve <code>turkish-plugin<\/code> i\u00e7indeki servis sa\u011flay\u0131c\u0131lar\u0131 otomatik olarak ke\u015ffedilecek ve kullan\u0131lacakt\u0131r. Yeni bir dil deste\u011fi eklemek istedi\u011finizde, sadece yeni bir plugin mod\u00fcl\u00fc olu\u015fturup <code>META-INF\/services<\/code> dosyas\u0131n\u0131 eklemeniz ve bu mod\u00fcl\u00fc uygulaman\u0131n classpath'ine dahil etmeniz yeterli olacakt\u0131r.<\/p>\n<h2>Ger\u00e7ek D\u00fcnya Senaryosu: Bir Raporlama Uygulamas\u0131nda Eklenti Entegrasyonu<\/h2>\n<p>\u00d6nceki b\u00f6l\u00fcmde basit bir mesajla\u015fma uygulamas\u0131 \u00fczerinden Java SPI'nin temel prensiplerini ad\u0131m ad\u0131m \u00f6\u011frendik. \u015eimdi bu bilgiyi, daha karma\u015f\u0131k ve ger\u00e7ek d\u00fcnyaya yak\u0131n bir senaryoda uygulayarak peki\u015ftirelim: Farkl\u0131 formatlarda raporlar \u00fcretebilen bir raporlama uygulamas\u0131.<\/p>\n<p>Bir\u00e7ok i\u015f uygulamas\u0131nda, verilerin farkl\u0131 formatlarda (PDF, CSV, HTML, JSON vb.) d\u0131\u015fa aktar\u0131lmas\u0131 veya raporlanmas\u0131 istenir. Ba\u015flang\u0131\u00e7ta uygulaman\u0131z sadece PDF raporlar\u0131 \u00fcretiyor olabilir. Ancak zamanla, i\u015f birimleri CSV format\u0131nda veri istediyse veya pazarlama departman\u0131 HTML tabanl\u0131, daha g\u00f6rsel raporlara ihtiya\u00e7 duyduysa ne yapacaks\u0131n\u0131z? Her yeni format i\u00e7in ana raporlama motorunu de\u011fi\u015ftirmek veya devasa <code>if-else<\/code> bloklar\u0131 eklemek, kodun s\u00fcrd\u00fcr\u00fclebilirli\u011fini h\u0131zla d\u00fc\u015f\u00fcrecektir.<\/p>\n<p>\u0130\u015fte tam da bu noktada Java SPI tabanl\u0131 bir eklenti mimarisi devreye girer. Raporlama uygulamam\u0131z\u0131n \u00e7ekirde\u011fini, yeni rapor formatlar\u0131n\u0131 kolayca entegre edebilecek \u015fekilde tasarlayabiliriz. Bu, uygulaman\u0131n hem esnekli\u011fini art\u0131r\u0131r hem de gelecekteki de\u011fi\u015fikliklere kar\u015f\u0131 daha dayan\u0131kl\u0131 olmas\u0131n\u0131 sa\u011flar.<\/p>\n<p><strong>Vaka Analizi: \u00c7ok Formatl\u0131 Raporlama Uygulamas\u0131<\/strong><\/p>\n<p>Uygulamam\u0131z\u0131n temel amac\u0131, kullan\u0131c\u0131dan al\u0131nan verileri i\u015fleyip se\u00e7ilen formata g\u00f6re bir rapor \u00e7\u0131kt\u0131s\u0131 vermektir. Her bir rapor format\u0131 (PDF, CSV, HTML) ayr\u0131 bir eklenti olarak ele al\u0131nacakt\u0131r. Ana uygulama, mevcut t\u00fcm rapor formatlar\u0131n\u0131 ke\u015ffedecek ve kullan\u0131c\u0131n\u0131n se\u00e7imine g\u00f6re ilgili eklentiyi \u00e7al\u0131\u015ft\u0131racakt\u0131r.<\/p>\n<h3>Ad\u0131m 1: Raporlama Servis Aray\u00fcz\u00fcn\u00fc Tan\u0131mlama (API Mod\u00fcl\u00fc)<\/h3>\n<p><code>report-api<\/code> ad\u0131nda bir mod\u00fcl olu\u015ftural\u0131m. Bu mod\u00fcl, t\u00fcm raporlama eklentilerinin uymas\u0131 gereken s\u00f6zle\u015fmeyi i\u00e7erecek.<\/p>\n<p><code>report-api\/src\/main\/java\/com\/example\/report\/api\/ReportGenerator.java<\/code>:<\/p>\n<pre><code class=\"language-java\">package com.example.report.api;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface ReportGenerator {\n    \/**\n     * Bu rapor jenerat\u00f6r\u00fcn\u00fcn destekledi\u011fi format\u0131 d\u00f6nd\u00fcr\u00fcr.\n     * \u00d6rne\u011fin: \"pdf\", \"csv\", \"html\".\n     * @return Rapor format\u0131n\u0131n ad\u0131.\n     *\/\n    String getFormat();\n\n    \/**\n     * Verilen verileri kullanarak bir rapor olu\u015fturur ve d\u00f6nd\u00fcr\u00fcr.\n     * @param data Rapor i\u00e7in kullan\u0131lacak veriler (\u00f6rne\u011fin, sat\u0131r listesi, s\u00fctun haritalamas\u0131).\n     * @param outputFileName Raporun kaydedilece\u011fi dosya ad\u0131 (uzant\u0131s\u0131z).\n     * @return Olu\u015fturulan raporun dosya yolu.\n     * @throws ReportGenerationException Rapor olu\u015fturma s\u0131ras\u0131nda bir hata olu\u015fursa.\n     *\/\n    String generateReport(List<Map<String, String>> data, String outputFileName) throws ReportGenerationException;\n}\n<\/pre>\n<p><\/code><\/p>\n<p>Rapor olu\u015fturma s\u0131ras\u0131nda olu\u015fabilecek hatalar i\u00e7in \u00f6zel bir istisna s\u0131n\u0131f\u0131 tan\u0131mlayal\u0131m:<\/p>\n<p><code>report-api\/src\/main\/java\/com\/example\/report\/api\/ReportGenerationException.java<\/code>:<\/p>\n<pre><code class=\"language-java\">package com.example.report.api;\n\npublic class ReportGenerationException extends Exception {\n    public ReportGenerationException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public ReportGenerationException(String message) {\n        super(message);\n    }\n}\n<\/pre>\n<p><\/code><\/p>\n<h3>Ad\u0131m 2: Servis Sa\u011flay\u0131c\u0131lar\u0131 Geli\u015ftirme (Plugin Mod\u00fclleri)<\/h3>\n<p>\u015eimdi <code>ReportGenerator<\/code> aray\u00fcz\u00fcn\u00fc uygulayan eklentileri olu\u015ftural\u0131m. Her eklenti ayr\u0131 bir Maven mod\u00fcl\u00fc olacak.<\/p>\n<p><strong>PDF Rapor Eklentisi (<code>pdf-report-plugin<\/code>):<\/strong><\/p>\n<p>Bu mod\u00fcl <code>report-api<\/code>'ye ba\u011f\u0131ml\u0131 olacak.<\/p>\n<p><code>pdf-report-plugin\/src\/main\/java\/com\/example\/report\/plugins\/PdfReportGeneratorImpl.java<\/code>:<\/p>\n<pre><code class=\"language-java\">package com.example.report.plugins;\n\nimport com.example.report.api.ReportGenerationException;\nimport com.example.report.api.ReportGenerator;\n\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\n\npublic class PdfReportGeneratorImpl implements ReportGenerator {\n    @Override\n    public String getFormat() {\n        return \"pdf\";\n    }\n\n    @Override\n    public String generateReport(List<Map<String, String>> data, String outputFileName) throws ReportGenerationException {\n        String filePath = outputFileName + \".pdf\";\n        try (FileWriter writer = new FileWriter(filePath)) {\n            writer.write(\"--- PDF Rapor Ba\u015flang\u0131c\u0131 ---\\n\");\n            writer.write(\"Ba\u015fl\u0131k: Sat\u0131\u015f Raporu\\n\");\n            writer.write(\"Veri:\\n\");\n            for (Map<String, String> row : data) {\n                writer.write(\"  - \");\n                row.forEach((key, value) -> {\n                    try {\n                        writer.write(key + \": \" + value + \", \");\n                    } catch (IOException e) {\n                        \/\/ ignore\n                    }\n                });\n                writer.write(\"\\n\");\n            }\n            writer.write(\"--- PDF Rapor Sonu ---\\n\");\n            System.out.println(\"PDF raporu olu\u015fturuldu: \" + filePath);\n            return filePath;\n        } catch (IOException e) {\n            throw new ReportGenerationException(\"PDF raporu olu\u015fturulurken hata olu\u015ftu.\", e);\n        }\n    }\n}\n<\/pre>\n<p><\/code><\/p>\n<p><code>pdf-report-plugin\/src\/main\/resources\/META-INF\/services\/com.example.report.api.ReportGenerator<\/code> dosyas\u0131:<\/p>\n<pre><code>com.example.report.plugins.PdfReportGeneratorImpl\n<\/pre>\n<p><\/code><\/p>\n<p><strong>CSV Rapor Eklentisi (<code>csv-report-plugin<\/code>):<\/strong><\/p>\n<p>Bu mod\u00fcl de <code>report-api<\/code>'ye ba\u011f\u0131ml\u0131 olacak.<\/p>\n<p><code>csv-report-plugin\/src\/main\/java\/com\/example\/report\/plugins\/CsvReportGeneratorImpl.java<\/code>:<\/p>\n<pre><code class=\"language-java\">package com.example.report.plugins;\n\nimport com.example.report.api.ReportGenerationException;\nimport com.example.report.api.ReportGenerator;\n\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\npublic class CsvReportGeneratorImpl implements ReportGenerator {\n    @Override\n    public String getFormat() {\n        return \"csv\";\n    }\n\n    @Override\n    public String generateReport(List<Map<String, String>> data, String outputFileName) throws ReportGenerationException {\n        String filePath = outputFileName + \".csv\";\n        try (FileWriter writer = new FileWriter(filePath)) {\n            if (data != null && !data.isEmpty()) {\n                \/\/ S\u00fctun ba\u015fl\u0131klar\u0131n\u0131 yaz\n                writer.write(data.get(0).keySet().stream().collect(Collectors.joining(\",\")) + \"\\n\");\n                \/\/ Veri sat\u0131rlar\u0131n\u0131 yaz\n                for (Map<String, String> row : data) {\n                    writer.write(row.values().stream().collect(Collectors.joining(\",\")) + \"\\n\");\n                }\n            }\n            System.out.println(\"CSV raporu olu\u015fturuldu: \" + filePath);\n            return filePath;\n        } catch (IOException e) {\n            throw new ReportGenerationException(\"CSV raporu olu\u015fturulurken hata olu\u015ftu.\", e);\n        }\n    }\n}\n<\/pre>\n<p><\/code><\/p>\n<p><code>csv-report-plugin\/src\/main\/resources\/META-INF\/services\/com.example.report.api.ReportGenerator<\/code> dosyas\u0131:<\/p>\n<pre><code>com.example.report.plugins.CsvReportGeneratorImpl\n<\/pre>\n<p><\/code><\/p>\n<h3>Ad\u0131m 3: Ana Uygulama (<code>report-app<\/code>)<\/h3>\n<p>Ana uygulama mod\u00fcl\u00fc, <code>report-api<\/code>, <code>pdf-report-plugin<\/code> ve <code>csv-report-plugin<\/code> mod\u00fcllerine ba\u011f\u0131ml\u0131 olacak. Bu uygulama, <code>ServiceLoader<\/code> kullanarak t\u00fcm rapor jenerat\u00f6rlerini ke\u015ffedecek ve kullan\u0131c\u0131dan format se\u00e7imi alarak ilgili raporu olu\u015fturacakt\u0131r.<\/p>\n<p><code>report-app\/src\/main\/java\/com\/example\/report\/app\/ReportApplication.java<\/code>:<\/p>\n<pre><code class=\"language-java\">package com.example.report.app;\n\nimport com.example.report.api.ReportGenerationException;\nimport com.example.report.api.ReportGenerator;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.ServiceLoader;\nimport java.util.Scanner;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\npublic class ReportApplication {\n    public static void main(String[] args) {\n        System.out.println(\"Raporlama Uygulamas\u0131 Ba\u015flat\u0131l\u0131yor...\");\n\n        \/\/ \u00d6rnek veri\n        List<Map<String, String>> sampleData = new ArrayList<>();\n        Map<String, String> row1 = new HashMap<>();\n        row1.put(\"ID\", \"1\");\n        row1.put(\"\u00dcr\u00fcn\", \"Laptop\");\n        row1.put(\"Miktar\", \"5\");\n        row1.put(\"Fiyat\", \"1200\");\n        sampleData.add(row1);\n\n        Map<String, String> row2 = new HashMap<>();\n        row2.put(\"ID\", \"2\");\n        row2.put(\"\u00dcr\u00fcn\", \"Mouse\");\n        row2.put(\"Miktar\", \"10\");\n        row2.put(\"Fiyat\", \"25\");\n        sampleData.add(row2);\n\n        \/\/ Servis sa\u011flay\u0131c\u0131lar\u0131n\u0131 y\u00fckle\n        ServiceLoader<ReportGenerator> loader = ServiceLoader.load(ReportGenerator.class);\n        Map<String, ReportGenerator> generators = new HashMap<>();\n        for (ReportGenerator generator : loader) {\n            generators.put(generator.getFormat().toLowerCase(), generator);\n        }\n\n        if (generators.isEmpty()) {\n            System.out.println(\"Hi\u00e7bir rapor jenerat\u00f6r\u00fc eklentisi bulunamad\u0131! Uygulama sonland\u0131r\u0131l\u0131yor.\");\n            return;\n        }\n\n        System.out.println(\"Mevcut Rapor Formatlar\u0131: \" + generators.keySet().stream().collect(Collectors.joining(\", \")));\n\n        try (Scanner scanner = new Scanner(System.in)) {\n            System.out.print(\"L\u00fctfen bir rapor format\u0131 se\u00e7in (\" + generators.keySet().stream().collect(Collectors.joining(\"\/\")) + \"): \");\n            String chosenFormat = scanner.nextLine().toLowerCase();\n\n            ReportGenerator selectedGenerator = generators.get(chosenFormat);\n            if (selectedGenerator == null) {\n                System.out.println(\"Ge\u00e7ersiz format se\u00e7imi: \" + chosenFormat);\n                return;\n            }\n\n            System.out.print(\"Rapor dosya ad\u0131n\u0131 girin (uzant\u0131s\u0131z): \");\n            String outputFileName = scanner.nextLine();\n\n            try {\n                String reportPath = selectedGenerator.generateReport(sampleData, outputFileName);\n                System.out.println(\"Rapor ba\u015far\u0131yla olu\u015fturuldu: \" + reportPath);\n            } catch (ReportGenerationException e) {\n                System.err.println(\"Rapor olu\u015fturulurken bir hata olu\u015ftu: \" + e.getMessage());\n                e.printStackTrace();\n            }\n        }\n    }\n}\n<\/pre>\n<p><\/code><\/p>\n<p>Bu \u00f6rnekte, ana uygulama kullan\u0131c\u0131dan hangi rapor format\u0131n\u0131 istedi\u011fini sorar. Ard\u0131ndan, <code>ServiceLoader<\/code> taraf\u0131ndan ke\u015ffedilen uygun <code>ReportGenerator<\/code> eklentisini bulur ve raporu olu\u015fturur. E\u011fer gelecekte XML veya JSON format\u0131nda raporlar eklemek istersek, sadece yeni bir eklenti mod\u00fcl\u00fc olu\u015fturup <code>ReportGenerator<\/code> aray\u00fcz\u00fcn\u00fc uygulamam\u0131z ve <code>META-INF\/services<\/code> dosyas\u0131n\u0131 eklememiz yeterli olacakt\u0131r. Ana uygulama kodunda hi\u00e7bir de\u011fi\u015fiklik yapmam\u0131za gerek kalmayacakt\u0131r. Bu, Java SPI'nin sa\u011flad\u0131\u011f\u0131 ger\u00e7ek d\u00fcnya geni\u015fletilebilirli\u011finin g\u00fc\u00e7l\u00fc bir \u00f6rne\u011fidir.<\/p>\n<h2>Performans ve G\u00fcvenlik: \u0130leri D\u00fczey \u0130pu\u00e7lar\u0131<\/h2>\n<p>Java SPI mekanizmas\u0131, basit eklenti mimarileri olu\u015fturmak i\u00e7in harika bir temel sunar. Ancak her sistemde oldu\u011fu gibi, b\u00fcy\u00fck \u00f6l\u00e7ekli uygulamalarda veya hassas verilerle \u00e7al\u0131\u015f\u0131rken performans ve g\u00fcvenlik konular\u0131n\u0131 g\u00f6z \u00f6n\u00fcnde bulundurmak \u00f6nemlidir. Bu b\u00f6l\u00fcmde, SPI tabanl\u0131 eklenti sistemlerinizin daha verimli ve g\u00fcvenli \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flayacak ileri d\u00fczey ipu\u00e7lar\u0131na de\u011finece\u011fiz.<\/p>\n<h3>Eklenti Ke\u015ffi ve Y\u00fckleme Performans\u0131<\/h3>\n<p><code>ServiceLoader<\/code>, varsay\u0131lan olarak eklentileri tembel (lazy) bir \u015fekilde y\u00fckler. Yani, bir eklentinin \u00f6rne\u011fi (instance) sadece ilk kez ihtiya\u00e7 duyuldu\u011funda olu\u015fturulur. Bu, bir\u00e7ok senaryo i\u00e7in iyi bir performans karakteristi\u011fidir \u00e7\u00fcnk\u00fc t\u00fcm eklentilerin uygulaman\u0131n ba\u015flang\u0131c\u0131nda y\u00fcklenmesi gereksiz kaynak t\u00fcketimine yol a\u00e7abilir. Ancak, baz\u0131 durumlar i\u00e7in bu davran\u0131\u015f iyile\u015ftirilebilir:<\/p>\n<ul>\n<li>\n            <strong>Uygulama Ba\u015flat\u0131ld\u0131\u011f\u0131nda Eklentileri \u00d6nbellekleme:<\/strong> E\u011fer uygulaman\u0131z\u0131n eklentilere s\u0131k\u00e7a eri\u015fmesi gerekiyorsa ve ilk eri\u015fimdeki gecikmeyi ortadan kald\u0131rmak istiyorsan\u0131z, t\u00fcm eklentileri uygulaman\u0131n ba\u015flang\u0131c\u0131nda y\u00fckleyip bir <code>Map<\/code> veya <code>List<\/code> i\u00e7inde \u00f6nbelle\u011fe alabilirsiniz. Bu, <code>ServiceLoader<\/code>'\u0131n <code>META-INF\/services<\/code> dosyalar\u0131n\u0131 her seferinde yeniden taramas\u0131n\u0131 engeller. A\u015fa\u011f\u0131daki \u00f6rnekte, ana uygulaman\u0131n <code>main<\/code> metodunda t\u00fcm jenerat\u00f6rleri bir <code>Map<\/code>'e y\u00fckledi\u011fimiz gibi bir yakla\u015f\u0131m d\u00fc\u015f\u00fcn\u00fclebilir.<\/p>\n<pre><code class=\"language-java\">Map<String, ReportGenerator> cachedGenerators = new HashMap<>();\nfor (ReportGenerator generator : ServiceLoader.load(ReportGenerator.class)) {\n    cachedGenerators.put(generator.getFormat().toLowerCase(), generator);\n}\n\/\/ Art\u0131k istedi\u011finiz zaman cachedGenerators map'inden eklentilere eri\u015febilirsiniz.\n<\/pre>\n<p><\/code><br \/>\n            Bu, \u00f6zellikle bir\u00e7ok eklentiniz oldu\u011funda ve her birine s\u0131k\u00e7a eri\u015fim gerekiyorsa performans\u0131 art\u0131rabilir. Ancak, bu yakla\u015f\u0131m ba\u015flang\u0131\u00e7 y\u00fckleme s\u00fcresini art\u0131racakt\u0131r. Trade-off'lar\u0131 iyi de\u011ferlendirmek gerekir.\n        <\/li>\n<li>\n            <strong>Sadece Gerekli Eklentileri Y\u00fckleme:<\/strong> Bazen uygulaman\u0131z\u0131n \u00e7al\u0131\u015ft\u0131\u011f\u0131 ortama veya kullan\u0131c\u0131n\u0131n tercihlerine g\u00f6re belirli eklentileri hi\u00e7 y\u00fcklememeniz gerekebilir. <code>ServiceLoader<\/code> do\u011frudan bu mekanizmay\u0131 sa\u011flamasa da, eklentilerinizin y\u00fcklenmesi i\u00e7in gerekli JAR dosyalar\u0131n\u0131 classpath'e sadece gerekti\u011finde ekleyerek bunu dolayl\u0131 yoldan ba\u015farabilirsiniz. \u00d6rne\u011fin, dinamik ClassLoader'lar veya mod\u00fcler sistemler (JPMS) bu konuda daha geli\u015fmi\u015f kontrol sunabilir.\n        <\/li>\n<\/ul>\n<h3>Eklenti G\u00fcvenli\u011fi ve \u0130zolasyon<\/h3>\n<p>Harici kaynaklardan (\u00f6rne\u011fin \u00fc\u00e7\u00fcnc\u00fc taraf geli\u015ftiricilerden) gelen eklentileri kullan\u0131rken g\u00fcvenlik ciddi bir endi\u015fe kayna\u011f\u0131 olabilir. K\u00f6t\u00fc niyetli bir eklenti, ana uygulaman\u0131z\u0131n veya sisteminizin g\u00fcvenli\u011fini tehlikeye atabilir. Java SPI tek ba\u015f\u0131na kapsaml\u0131 bir g\u00fcvenlik modeli sa\u011flamasa da, birka\u00e7 stratejiyle riskleri azaltabilirsiniz:<\/p>\n<ul>\n<li>\n            <strong>Classloader \u0130zolasyonu:<\/strong> En yayg\u0131n ve etkili y\u00f6ntemlerden biri, her eklentiyi kendi <code>ClassLoader<\/code>'\u0131 i\u00e7inde y\u00fcklemektir. Bu sayede, bir eklentinin k\u00f6t\u00fc niyetli kodu di\u011fer eklentilere veya ana uygulamaya eri\u015femez. Java'da <code>URLClassLoader<\/code> kullanarak bu t\u00fcr bir izolasyon sa\u011flayabilirsiniz. Her eklenti i\u00e7in ayr\u0131 bir JAR dosyas\u0131n\u0131 okuyan bir <code>URLClassLoader<\/code> olu\u015fturabilir ve eklentiyi bu ClassLoader ile y\u00fckleyebilirsiniz. Bu, eklentinin kendi ba\u011f\u0131ml\u0131l\u0131klar\u0131n\u0131 izole etmesine de yard\u0131mc\u0131 olur. Ancak bu y\u00f6ntem karma\u015f\u0131kl\u0131\u011f\u0131 art\u0131r\u0131r ve ClassLoader hiyerar\u015fileriyle ilgili derinlemesine bilgi gerektirebilir.<\/p>\n<div class=\"expert-tip\">\n                Uzman \u0130pucu: Java Platform Module System (JPMS), yani Java 9 ve sonras\u0131 mod\u00fcl sistemi, ClassLoader izolasyonuna do\u011fal bir \u00e7\u00f6z\u00fcm sunar. Her mod\u00fcl kendi ba\u015f\u0131na bir \"sandbox\" gibi davranabilir ve hangi kaynaklara eri\u015febilece\u011fi (<code>exports<\/code> ve <code>requires<\/code> direktifleriyle) a\u00e7\u0131k\u00e7a tan\u0131mlan\u0131r. E\u011fer Java 9 ve \u00fczeri bir versiyon kullan\u0131yorsan\u0131z, SPI ile JPMS'i entegre etmek g\u00fcvenlik ve mod\u00fclerlik a\u00e7\u0131s\u0131ndan b\u00fcy\u00fck faydalar sa\u011flayabilir.\n            <\/div>\n<\/li>\n<li>\n            <strong>G\u00fcvenlik Politikalar\u0131 (<code>SecurityManager<\/code>):<\/strong> Java'n\u0131n <code>SecurityManager<\/code>'\u0131, kodun belirli eylemleri (dosya okuma\/yazma, a\u011f ba\u011flant\u0131s\u0131 kurma vb.) ger\u00e7ekle\u015ftirip ger\u00e7ekle\u015ftiremeyece\u011fini kontrol etmek i\u00e7in kullan\u0131labilir. Bir eklentiyi y\u00fcklemeden \u00f6nce veya y\u00fckledikten sonra, bu eklentiye \u00f6zg\u00fc bir g\u00fcvenlik politikas\u0131 tan\u0131mlayarak potansiyel zararl\u0131 aktivitelerini k\u0131s\u0131tlayabilirsiniz. Ancak, Java 17'den itibaren <code>SecurityManager<\/code>'\u0131n kullan\u0131m\u0131n\u0131n kald\u0131r\u0131lmas\u0131 planland\u0131\u011f\u0131 i\u00e7in, bu yakla\u015f\u0131m uzun vadede s\u00fcrd\u00fcr\u00fclebilir de\u011fildir ve yerine JPMS gibi daha modern mod\u00fclerlik ve g\u00fcvenlik mekanizmalar\u0131 tercih edilmelidir.\n        <\/li>\n<li>\n            <strong>Giri\u015f Do\u011frulama (Input Validation):<\/strong> Eklentilerin uygulaman\u0131zla etkile\u015fime girdi\u011fi her noktada, giri\u015fleri dikkatlice do\u011frulaman\u0131z \u00f6nemlidir. K\u00f6t\u00fc niyetli bir eklenti, yanl\u0131\u015f veya bozuk veriler sa\u011flayarak ana uygulaman\u0131n \u00e7\u00f6kmesine veya hatal\u0131 \u00e7al\u0131\u015fmas\u0131na neden olabilir. Aray\u00fczlerinizdeki parametrelerin ge\u00e7erlili\u011fini her zaman kontrol edin.\n        <\/li>\n<li>\n            <strong>Kod \u0130ncelemesi ve Dijital \u0130mza:<\/strong> E\u011fer eklentileri harici kaynaklardan al\u0131yorsan\u0131z, m\u00fcmk\u00fcnse kod incelemesi yap\u0131n veya eklentilerin g\u00fcvenilir bir kaynaktan geldi\u011fini do\u011frulamak i\u00e7in dijital imzalar\u0131 kullan\u0131n. Bu, y\u00fcr\u00fctmeden \u00f6nce potansiyel g\u00fcvenlik risklerini belirlemenin en kesin yoludur.\n        <\/li>\n<\/ul>\n<p>Sonu\u00e7 olarak, Java SPI basit ve g\u00fc\u00e7l\u00fc bir eklenti mekanizmas\u0131 sunsa da, ger\u00e7ek d\u00fcnya uygulamalar\u0131nda performans ve g\u00fcvenlik gibi konular\u0131 g\u00f6z ard\u0131 etmemek gerekir. \u00d6zellikle eklentileri g\u00fcvensiz kaynaklardan al\u0131yorsan\u0131z, ClassLoader izolasyonu ve JPMS gibi modern Java \u00f6zelliklerini kullanarak sa\u011flam bir g\u00fcvenlik duru\u015fu sergilemek kritik \u00f6neme sahiptir.<\/p>\n<h2>Sonu\u00e7 ve Gelecek Perspektifleri<\/h2>\n<p>Bu makale boyunca, Java SPI mekanizmas\u0131n\u0131n temel prensiplerini, eklenti mimarisinin faydalar\u0131n\u0131 ve ad\u0131m ad\u0131m basit bir eklenti sisteminin nas\u0131l in\u015fa edilece\u011fini detayl\u0131ca inceledik. Uygulama esnekli\u011fini art\u0131rmak, mod\u00fclerli\u011fi te\u015fvik etmek ve \u00fc\u00e7\u00fcnc\u00fc taraf entegrasyonlar\u0131na kap\u0131 a\u00e7mak gibi bir\u00e7ok avantaj\u0131yla eklenti mimarileri, modern yaz\u0131l\u0131m geli\u015ftirmede vazge\u00e7ilmez bir yer tutmaktad\u0131r. Java SPI, bu hedeflere ula\u015fmak i\u00e7in d\u00fc\u015f\u00fck karma\u015f\u0131kl\u0131ktaki ve nispeten basit ihtiya\u00e7lar i\u00e7in olduk\u00e7a etkili bir \u00e7\u00f6z\u00fcm sunar.<\/p>\n<p>G\u00f6rd\u00fc\u011f\u00fcm\u00fcz gibi, <code>ServiceLoader<\/code> s\u0131n\u0131f\u0131 ve <code>META-INF\/services<\/code> konvansiyonu sayesinde, uygulamalar\u0131m\u0131z \u00e7al\u0131\u015fma zaman\u0131nda bilinen bir aray\u00fcz\u00fcn t\u00fcm implementasyonlar\u0131n\u0131 otomatik olarak ke\u015ffedebilir ve kullanabilir. Bu sayede, ana uygulama kodunu de\u011fi\u015ftirmeye gerek kalmadan yeni i\u015flevsellikler ekleyebiliriz. Mesajla\u015fma ve raporlama uygulamas\u0131 \u00f6rneklerimizle, bu mekanizman\u0131n nas\u0131l \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131 ve ger\u00e7ek d\u00fcnya senaryolar\u0131nda nas\u0131l uygulanabilece\u011fini somutla\u015ft\u0131rd\u0131k.<\/p>\n<p>Ancak, her ara\u00e7 gibi Java SPI'nin de kendine \u00f6zg\u00fc avantajlar\u0131 ve s\u0131n\u0131rl\u0131l\u0131klar\u0131 vard\u0131r. B\u00fcy\u00fck ve karma\u015f\u0131k projelerde, eklentilerin ya\u015fam d\u00f6ng\u00fcs\u00fc y\u00f6netimi, ba\u011f\u0131ml\u0131l\u0131k enjeksiyonu veya daha kat\u0131 g\u00fcvenlik sandbox'lar\u0131 gibi ileri d\u00fczey gereksinimler ortaya \u00e7\u0131kt\u0131\u011f\u0131nda, OSGi veya Spring Framework gibi daha kapsaml\u0131 \u00e7\u00f6z\u00fcmlere y\u00f6nelmek gerekebilir. \u00d6te yandan, Java 9 ile hayat\u0131m\u0131za giren Java Platform Module System (JPMS), eklenti mimarileri i\u00e7in yeni ve g\u00fc\u00e7l\u00fc bir boyut katm\u0131\u015ft\u0131r. JPMS, mod\u00fcller aras\u0131 ili\u015fkileri daha kat\u0131 bir \u015fekilde tan\u0131mlayarak, kaps\u00fclleme ve g\u00fcvenlik a\u00e7\u0131s\u0131ndan SPI'ye k\u0131yasla \u00f6nemli iyile\u015ftirmeler sunar. Gelecekte, SPI'nin JPMS ile birlikte kullan\u0131lmas\u0131, daha robust ve y\u00f6netilebilir eklenti sistemleri olu\u015fturman\u0131n anahtar\u0131 olabilir.<\/p>\n<p>\u00d6zetle, Java SPI, esnek ve geni\u015fletilebilir uygulamalar geli\u015ftirmek isteyen Java geli\u015ftiricileri i\u00e7in \u00f6\u011frenmesi kolay ve hemen uygulanabilir bir tekniktir. Uygulaman\u0131z\u0131n ihtiya\u00e7lar\u0131na g\u00f6re bu basit mekanizmay\u0131 bir ba\u015flang\u0131\u00e7 noktas\u0131 olarak kullanabilir, gerekti\u011finde daha geli\u015fmi\u015f \u00e7\u00f6z\u00fcmlerle birle\u015ftirebilirsiniz. Unutmay\u0131n, iyi tasarlanm\u0131\u015f bir eklenti mimarisi, uygulaman\u0131z\u0131n uzun \u00f6m\u00fcrl\u00fc ve de\u011fi\u015fen gereksinimlere uyum sa\u011flayabilen bir yap\u0131ya sahip olmas\u0131n\u0131 garantiler.<\/p>\n<h3>S\u0131k\u00e7a Sorulan Sorular<\/h3>\n<ul>\n<li>\n            <strong>S: Java SPI'nin ana avantaj\u0131 nedir?<\/strong><\/p>\n<p><strong>C:<\/strong> Java SPI'nin ana avantaj\u0131, bir uygulaman\u0131n temel kodunu de\u011fi\u015ftirmeden yeni servis sa\u011flay\u0131c\u0131lar\u0131n\u0131 (eklentileri) dinamik olarak ke\u015ffedip y\u00fckleyebilmesidir. Bu, uygulaman\u0131n mod\u00fclerli\u011fini, esnekli\u011fini ve geni\u015fletilebilirli\u011fini \u00f6nemli \u00f6l\u00e7\u00fcde art\u0131r\u0131r, b\u00f6ylece bak\u0131m kolayla\u015f\u0131r ve yeni \u00f6zelliklerin eklenmesi h\u0131zlan\u0131r.<\/p>\n<\/li>\n<li>\n            <strong>S: <code>ServiceLoader<\/code> nas\u0131l servis sa\u011flay\u0131c\u0131lar\u0131n\u0131 bulur?<\/strong><\/p>\n<p><strong>C:<\/strong> <code>ServiceLoader<\/code>, \u00e7al\u0131\u015fma zaman\u0131nda (runtime) classpath \u00fczerinde bulunan t\u00fcm JAR dosyalar\u0131n\u0131n i\u00e7indeki <code>META-INF\/services\/<\/code> dizinini tarar. Bu dizin alt\u0131nda, servis aray\u00fcz\u00fcn\u00fcn tam nitelikli ad\u0131n\u0131 ta\u015f\u0131yan dosyalara bakar. Bu dosyalar\u0131n i\u00e7inde, ilgili aray\u00fcz\u00fc uygulayan somut s\u0131n\u0131f adlar\u0131 listelenir. <code>ServiceLoader<\/code> bu s\u0131n\u0131f adlar\u0131n\u0131 okuyarak sa\u011flay\u0131c\u0131lar\u0131 y\u00fckler.<\/p>\n<\/li>\n<li>\n            <strong>S: Java SPI, OSGi gibi daha geli\u015fmi\u015f mod\u00fclerlik framework'leriyle kar\u015f\u0131la\u015ft\u0131r\u0131ld\u0131\u011f\u0131nda nerede durur?<\/strong><\/p>\n<p><strong>C:<\/strong> Java SPI, servis ke\u015ffi i\u00e7in basit ve do\u011frudan bir mekanizmad\u0131r. Daha \u00e7ok \"plug-and-play\" (tak ve \u00e7al\u0131\u015ft\u0131r) tarz\u0131 eklentiler i\u00e7in uygundur ve genellikle tek y\u00f6nl\u00fc bir ba\u011f\u0131ml\u0131l\u0131k (uygulama eklentiye ba\u011f\u0131ml\u0131) modelini takip eder. OSGi gibi framework'ler ise \u00e7ok daha kapsaml\u0131d\u0131r; eklentilerin (bundle'lar\u0131n) ya\u015fam d\u00f6ng\u00fcs\u00fc y\u00f6netimi (ba\u015flatma, durdurma, g\u00fcncelleme), mod\u00fcller aras\u0131 dinamik ba\u011f\u0131ml\u0131l\u0131k enjeksiyonu, s\u00fcr\u00fcm kontrol\u00fc ve geli\u015fmi\u015f ClassLoader izolasyonu gibi geli\u015fmi\u015f \u00f6zellikler sunar. SPI basit eklenti ihtiya\u00e7lar\u0131 i\u00e7in yeterliyken, OSGi daha dinamik ve karma\u015f\u0131k mod\u00fcler ortamlar i\u00e7in tercih edilir.<\/p>\n<\/li>\n<li>\n            <strong>S: Bir eklentiye ba\u011f\u0131ml\u0131l\u0131klar\u0131 nas\u0131l enjekte ederim?<\/strong><\/p>\n<p><strong>C:<\/strong> Java SPI mekanizmas\u0131 kendi ba\u015f\u0131na bir ba\u011f\u0131ml\u0131l\u0131k enjeksiyonu (DI) sistemi sa\u011flamaz. <code>ServiceLoader<\/code>, varsay\u0131lan olarak servis sa\u011flay\u0131c\u0131 s\u0131n\u0131flar\u0131n\u0131n parametresiz kurucusunu \u00e7a\u011f\u0131rarak bir \u00f6rnek olu\u015fturur. E\u011fer eklentilerinizin ba\u015fka ba\u011f\u0131ml\u0131l\u0131klar\u0131 varsa, bunlar\u0131 eklentinin kendi i\u00e7inde y\u00f6netmeniz (\u00f6rne\u011fin, manuel olarak olu\u015fturmak) veya Spring, Google Guice gibi bir DI framework'\u00fcn\u00fc eklentilerinize entegre etmeniz gerekir. Ana uygulaman\u0131z bir DI framework'\u00fc kullan\u0131yorsa, eklentilerinizi y\u00fckledikten sonra bu framework'\u00fcn kapsay\u0131c\u0131s\u0131na ekleyerek ba\u011f\u0131ml\u0131l\u0131k enjeksiyonunu sa\u011flaman\u0131z m\u00fcmk\u00fcnd\u00fcr.<\/p>\n<\/li>\n<li>\n            <strong>S: Birden fazla eklenti ayn\u0131 aray\u00fcz\u00fc uygulad\u0131\u011f\u0131nda ne olur?<\/strong><\/p>\n<p><strong>C:<\/strong> <code>ServiceLoader.load()<\/code> metodu, ayn\u0131 aray\u00fcz\u00fc uygulayan t\u00fcm servis sa\u011flay\u0131c\u0131lar\u0131n\u0131 i\u00e7eren bir <code>Iterator<\/code> (veya <code>Iterable<\/code>) d\u00f6nd\u00fcr\u00fcr. Yani, birden fazla eklenti varsa, hepsi y\u00fcklenir ve uygulaman\u0131z\u0131n eri\u015fimine sunulur. Uygulaman\u0131z\u0131n bu sa\u011flay\u0131c\u0131lar aras\u0131ndan hangisini veya hangilerini kullanaca\u011f\u0131na karar vermesi gerekir. \u00d6rne\u011fin, bir \u00f6nceki raporlama \u00f6rne\u011fimizde oldu\u011fu gibi, eklentilerin sa\u011flad\u0131\u011f\u0131 bir \"format\" \u00f6zelli\u011fine g\u00f6re uygun olan\u0131 se\u00e7ebilir veya t\u00fcm\u00fcn\u00fc s\u0131rayla \u00e7al\u0131\u015ft\u0131rabilir.<\/p>\n<\/li>\n<\/ul>\n<p><\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Uygulamalar\u0131n\u0131z\u0131 daha mod\u00fcler ve esnek hale getirmek ister misiniz? Java SPI mekanizmas\u0131 ile kendi basit eklenti mimarinizi ad\u0131m&hellip;","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[1408],"tags":[],"class_list":{"0":"post-35526","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-java","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?<\/title>\n<meta name=\"description\" content=\"Uygulamalar\u0131n\u0131z\u0131 daha mod\u00fcler ve esnek hale getirmek ister misiniz? Java SPI mekanizmas\u0131 ile kendi basit eklenti mimarinizi ad\u0131m ad\u0131m nas\u0131l kuraca\u011f\u0131n\u0131z\u0131 ke\u015ffedin ve kodunuzu gelece\u011fe haz\u0131rlay\u0131n.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?\" \/>\n<meta property=\"og:description\" content=\"Uygulamalar\u0131n\u0131z\u0131 daha mod\u00fcler ve esnek hale getirmek ister misiniz? Java SPI mekanizmas\u0131 ile kendi basit eklenti mimarinizi ad\u0131m ad\u0131m nas\u0131l kuraca\u011f\u0131n\u0131z\u0131 ke\u015ffedin ve kodunuzu gelece\u011fe haz\u0131rlay\u0131n.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-11-30T16:01:06+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"27 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?\",\"datePublished\":\"2025-11-30T16:01:06+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/\"},\"wordCount\":4229,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"Java\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/\",\"name\":\"Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-11-30T16:01:06+00:00\",\"description\":\"Uygulamalar\u0131n\u0131z\u0131 daha mod\u00fcler ve esnek hale getirmek ister misiniz? Java SPI mekanizmas\u0131 ile kendi basit eklenti mimarinizi ad\u0131m ad\u0131m nas\u0131l kuraca\u011f\u0131n\u0131z\u0131 ke\u015ffedin ve kodunuzu gelece\u011fe haz\u0131rlay\u0131n.\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?","description":"Uygulamalar\u0131n\u0131z\u0131 daha mod\u00fcler ve esnek hale getirmek ister misiniz? Java SPI mekanizmas\u0131 ile kendi basit eklenti mimarinizi ad\u0131m ad\u0131m nas\u0131l kuraca\u011f\u0131n\u0131z\u0131 ke\u015ffedin ve kodunuzu gelece\u011fe haz\u0131rlay\u0131n.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/","og_locale":"tr_TR","og_type":"article","og_title":"Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?","og_description":"Uygulamalar\u0131n\u0131z\u0131 daha mod\u00fcler ve esnek hale getirmek ister misiniz? Java SPI mekanizmas\u0131 ile kendi basit eklenti mimarinizi ad\u0131m ad\u0131m nas\u0131l kuraca\u011f\u0131n\u0131z\u0131 ke\u015ffedin ve kodunuzu gelece\u011fe haz\u0131rlay\u0131n.","og_url":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-11-30T16:01:06+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"27 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?","datePublished":"2025-11-30T16:01:06+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/"},"wordCount":4229,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["Java"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/","url":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/","name":"Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-11-30T16:01:06+00:00","description":"Uygulamalar\u0131n\u0131z\u0131 daha mod\u00fcler ve esnek hale getirmek ister misiniz? Java SPI mekanizmas\u0131 ile kendi basit eklenti mimarinizi ad\u0131m ad\u0131m nas\u0131l kuraca\u011f\u0131n\u0131z\u0131 ke\u015ffedin ve kodunuzu gelece\u011fe haz\u0131rlay\u0131n.","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/java-spi-ile-basit-eklenti-mimarisi-nasil-olusturulur\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Java SPI ile Basit Eklenti Mimarisi Nas\u0131l Olu\u015fturulur?"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/35526","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=35526"}],"version-history":[{"count":0,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/35526\/revisions"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=35526"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=35526"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=35526"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}