🔥 FREE PRO OFFER OnlyLink.click Pro Version is 100% Free of Cost till 31 December, 2026! Claim Free Pro

CDI ile Quarkus'ta Bağımlılık Enjeksiyonu: ArC, Kapsamlar, Niteleyiciler ve Oluşturma Zamanı Enjeksiyonu

CDI ile Quarkus'ta Bağımlılık Enjeksiyonu: ArC, Kapsamlar, Niteleyiciler ve Oluşturma Zamanı Enjeksiyonu

Bağımlılık Enjeksiyonu (DI), modern kurumsal Java uygulaması geliştirmenin temelidir. Yıllar boyunca Java geliştiricileri, bileşen yaşam döngülerini ayırmak, hizmet bağımlılıklarını yönetmek ve yapılandırma özelliklerini eklemek için Spring IoC (Kontrolün Tersine Dönüştürülmesi) veya Hibernate Weld veya OpenWebBeans gibi standart Jakarta EE CDI (Bağlamlar ve Bağlamlar Enjeksiyonu) kapsayıcılarına güvendi.

Ancak kurumsal uygulamalar bulutta yerel mikro hizmetlere, Docker ve Kubernetes ile konteynerleştirmeye ve sunucusuz yürütme modellerine (AWS Lambda, Knative) doğru geçiş yaptıkça, geleneksel bağımlılık enjeksiyon konteynerleri kritik bir kusuru ortaya çıkardı: yoğun çalışma zamanı yansıması ve yüksek bellek yükü.

Quarkus ve hafif CDI motoru ArC‘ye girin. Kubernetes ve GraalVM yerel derlemesi için sıfırdan oluşturulan Quarkus, yansımayı, sınıf yolu taramayı ve fasulye grafiği kablolamasını uygulama çalışma zamanından derleme zamanına kaydırarak bağımlılık enjeksiyonunu yeniden tanımlıyor.

Bu ayrıntılı kılavuzda ArC kapsayıcısının iç mekaniğini, CDI kapsamlarını, özel niteleyicileri, üreticileri, önleyicileri, olay odaklı gözlemcileri, programatik aramaları ve yüksek performanslı bulutta yerel Java uygulamaları yazmaya yönelik en iyi uygulamaları kapsayan CDI ile Quarkus’ta Bağımlılık Enjeksiyonunu keşfedeceğiz.


1. ArC’yi Anlamak: Quarkus Yapım Zamanı CDI Motoru

Standart Jakarta EE CDI kapsayıcıları tamamen uygulama başlangıcında çalışır. Eski bir uygulama önyüklendiğinde, CDI kapsayıcısı sınıf yolundaki her JAR’ı tarar, meta verileri ayrıştırır, Java Reflection (java.lang.reflect) kullanarak ek açıklamaları inceler, bellekte dinamik proxy’ler oluşturur ve bağımlılık grafiğini oluşturur. Bu dinamik yansıma, önemli miktarda RAM (Metaspace) tüketir ve soğuk başlatma önyükleme süresini artırır.

Quarkus bu darboğazı ArC (Jakarta CDI 4.0 özelliklerini temel alan bir yapım aşamasında CDI uygulaması) ile çözmektedir.

Reflection ile Geleneksel Çalışma Zamanı CDI'sı ve Quarkus ArC Yapı Zamanı Kablolaması

ArC’nin Standart CDI’dan Farkı:

  1. Derleme Zamanını Artırma: mvn package veya ./gradlew build sırasında ArC, tüm uygulama çekirdeklerini tarar, enjeksiyon noktalarını doğrular ve bağımlılık grafiğini önceden oluşturur.
  2. Zamandan Önce (AOT) Bayt Kodu Oluşturma: ArC, örnekleme, fasulye proxy’leri ve önleyiciler için doğrudan Java bayt kodu oluşturarak çalışma zamanında yansımayı ortadan kaldırır.
  3. Kullanılmayan Fasulye Budama (Ölü Kodun Ortadan Kaldırılması): Hiçbir zaman enjekte edilmeyen veya dinamik olarak referans verilmeyen herhangi bir CDI çekirdeği, derleme sırasında tanımlanır ve otomatik olarak son ikili dosyadan çıkarılarak bellek ayak izi azaltılır.
  4. GraalVM Yerel Görüntü Optimizasyonu: Fasulye kablolaması derleme sırasında çözüldüğü için Quarkus uygulamaları, sıfır yansıma yapılandırma ipuçlarıyla yerel yürütülebilir dosyalar halinde sorunsuz bir şekilde derlenir.

2. CDI Bean Kapsamları ve Yaşam Döngüsü Yönetimi

CDI’da Kapsam, bir fasulye örneğinin yaşam döngüsünü ve görünürlüğünü belirler. Quarkus ArC, derleme zamanı optimizasyonlarıyla standart Jakarta CDI kapsamlarını destekler.

Quarkus CDI Bean Kapsamları ve Yaşam Döngüleri Diyagramı

Quarkus’taki Birincil CDI Kapsamları:

Kapsam Açıklaması Yaşam Döngüsü ve Davranış Proxy Oluşturma En İyi Kullanım Durumu
@ApplicationScoped Uygulama başına tek örnek. İlk çalıştırmada tembel başlatma. Durum tüm başlıklarda paylaşıldı. İstemci Proxy’si Oluşturuldu Durum bilgisi olmayan hizmetler, depolar, yapılandırmalar.
@RequestScoped Örnek, tek bir HTTP isteğine veya olay çağrısına bağlıdır. İstek tamamlandığında yok edilir. İstemci Proxy’si Oluşturuldu Kullanıcı oturumları, istek bağlam verileri, güvenlik belirteçleri.
@Bağımlı Hiçbiri belirtilmemişse varsayılan kapsam. Örnek doğrudan enjekte edilen çekirdeğin ömrüne bağlıdır. Proxy Yok (Doğrudan Örnek) Yardımcı fayda sınıfları, geçici devlet sahipleri.
@Singleton Uygulama başına tek örnek. Hevesle veya tembelce örneklendi. İstemci proxy sarmalayıcısı yok. Proxy Yok (Doğrudan Örnek) İstemci proxy ek yükünden kaçınılması gereken yüksek performanslı singletonlar.
@Kaldırılamaz ArC’ye derleme zamanı optimizasyonu sırasında çekirdeği çıkarmaması talimatını veren işaretleyici açıklama. Kapsama bağlıdır Dinamik arama hedefleri veya yansıma referanslı fasulyeler.

Kod Örneği: Kapsamlı Fasulyelerin Bildirilmesi

package com.ghaznix.services;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.RequestScoped;
import java.util.UUID;

@ApplicationScoped
public class OrderProcessingService {
    
    public String processOrder(String orderId) {
        return "Order " + orderId + " processed successfully.";
    }
}

@RequestScoped
public class RequestContextHolder {
    private final String requestId = UUID.randomUUID().toString();

    public String getRequestId() {
        return requestId;
    }
}

3. Quarkus’ta Bağımlılık Enjeksiyon Kalıpları

Quarkus, standart jakarta.inject.Inject ek açıklamasını kullanarak birden fazla enjeksiyon stilini destekler.

A. Yapıcı Enjeksiyonu (Önerilen En İyi Uygulama)

Yapıcı enjeksiyonu değişmezliği garanti eder (final alanları), CDI kapsayıcılarına ihtiyaç duymadan birim testini basitleştirir ve bağımlılıkları açıkça ortaya koyar.

package com.ghaznix.resources;

import com.ghaznix.services.OrderProcessingService;
import jakarta.inject.Inject;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;

@Path("/orders")
public class OrderResource {

    private final OrderProcessingService orderService;

    // In Quarkus, if a class has a single constructor, @Inject is OPTIONAL!
    @Inject
    public OrderResource(OrderProcessingService orderService) {
        this.orderService = orderService;
    }

    @POST
    @Path("/{id}")
    public String checkout(@PathParam("id") String id) {
        return orderService.processOrder(id);
    }
}

Profesyonel İpucu: Quarkus ArC’de, eğer bir fasulyenin yalnızca tek yapıcısı varsa, @Inject ek açıklamasını tamamen atlayabilirsiniz. ArC onu otomatik olarak enjeksiyon yapıcısı olarak tanır.

B. Alan Enjeksiyonu

Alan enjeksiyonu kısa ve özdür ancak alanları değiştirilebilir hale getirir ve bağımsız birim testini karmaşık hale getirir.

@ApplicationScoped
public class NotificationService {

    @Inject
    EmailClient emailClient; // Field injection
}

4. Niteleyiciler ve Çoklu Uygulamaların Belirsizliğinin Ortaya Çıkarılması

Birden fazla fasulye aynı arayüzü uyguladığında CDI, derleme zamanında belirsiz bir bağımlılık istisnası oluşturur. Quarkus, hedef fasulye uygulamalarını güvenli bir şekilde çözmek için Niteleyicileri kullanır.

Özel Niteleyicileri Tanımlama

package com.ghaznix.payment;

import jakarta.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface PaymentType {
    Mode value();

    enum Mode {
        CREDIT_CARD,
        PAYPAL,
        CRYPTO
    }
}

Nitelikli Fasulyelerin Uygulanması

public interface PaymentProcessor {
    void process(double amount);
}

@ApplicationScoped
@PaymentType(PaymentType.Mode.CREDIT_CARD)
public class CreditCardProcessor implements PaymentProcessor {
    @Override
    public void process(double amount) {
        System.out.println("Processing Credit Card payment: $" + amount);
    }
}

@ApplicationScoped
@PaymentType(PaymentType.Mode.PAYPAL)
public class PayPalProcessor implements PaymentProcessor {
    @Override
    public void process(double amount) {
        System.out.println("Processing PayPal payment: $" + amount);
    }
}

Nitelikli Fasulyelerin Enjekte Edilmesi

@ApplicationScoped
public class CheckoutService {

    private final PaymentProcessor creditCardProcessor;
    private final PaymentProcessor payPalProcessor;

    @Inject
    public CheckoutService(
            @PaymentType(PaymentType.Mode.CREDIT_CARD) PaymentProcessor creditCardProcessor,
            @PaymentType(PaymentType.Mode.PAYPAL) PaymentProcessor payPalProcessor) {
        this.creditCardProcessor = creditCardProcessor;
        this.payPalProcessor = payPalProcessor;
    }
}

5. Üreticiler ve İmha Ediciler: Üçüncü Taraf Nesnelerinin Enjekte Edilmesi

Bazen üçüncü taraf kitaplıklardan (örneğin, AWS SDK istemcileri, Redis bağlantıları, özel yapılandırma çekirdekleri) @ApplicationScoped ile açıklanmayan sınıfları enjekte etmeniz gerekir. Quarkus bunu Üretici Yöntemleri ve Atıklayıcılar kullanarak hallediyor.

package com.ghaznix.config;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Disposes;
import jakarta.enterprise.inject.Produces;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

@ApplicationScoped
public class DatabaseConnectionProducer {

    @Produces
    @ApplicationScoped
    public Connection createDatabaseConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:postgresql://localhost:5432/mydb", "user", "pass");
    }

    // Disposer method called automatically when bean is destroyed
    public void closeConnection(@Disposes Connection connection) throws SQLException {
        if (connection != null && !connection.isClosed()) {
            connection.close();
        }
    }
}

6. CDI Durdurucuları: Yön Odaklı Programlama (AOP)

Durdurucular, iş mantığını kirletmeden, kesişen endişelerin (günlüğe kaydetme, denetim izleri, ölçümler, hız sınırlama) fasulye yöntemlerine eklenmesine olanak tanır.

Adım 1: Durdurucu Bağlamayı Tanımlayın

package com.ghaznix.interceptors;

import jakarta.interceptor.InterceptorBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@InterceptorBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface LogExecutionTime {
}

Adım 2: Durdurucu Mantığını Uygulama

package com.ghaznix.interceptors;

import jakarta.annotation.Priority;
import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;

@LogExecutionTime
@Interceptor
@Priority(Interceptor.Priority.APPLICATION)
public class LogExecutionTimeInterceptor {

    @AroundInvoke
    public Object logInvocation(InvocationContext context) throws Exception {
        long startTime = System.currentTimeMillis();
        try {
            return context.proceed();
        } finally {
            long duration = System.currentTimeMillis() - startTime;
            System.out.printf("[AUDIT] Method %s executed in %d ms%n",
                    context.getMethod().getName(), duration);
        }
    }
}

Adım 3: Hedef Fasulyelere Açıklama Ekleyin

@ApplicationScoped
public class AnalyticsService {

    @LogExecutionTime
    public void computeAggregates() {
        // Business computation
    }
}

Quarkus, derleme sırasında statik önleyici proxy’ler oluşturduğundan, yöntem çağırma yükü, Spring Boot’taki dinamik CGLIB çalışma zamanı proxy’lerine kıyasla neredeyse sıfırdır.


7. CDI Etkinlikleri ile Olay Odaklı Mimari

CDI, ayrıştırılmış süreç içi iletişim için yerleşik eşzamanlı ve eşzamansız olay yayımlama sağlar.

Etkinlikleri Yayınlama ve Gözlemleme

// 1. Define Event Payload
public record OrderCreatedEvent(String orderId, double totalAmount) {}

// 2. Publish Event
@ApplicationScoped
public class OrderService {

    @Inject
    Event<OrderCreatedEvent> orderEventPublisher;

    public void createOrder(String orderId, double amount) {
        // Create order logic...
        orderEventPublisher.fire(new OrderCreatedEvent(orderId, amount));
    }
}

// 3. Observe Event Synchronously or Asynchronously
@ApplicationScoped
public class InventoryObserver {

    public void onOrderCreated(@Observes OrderCreatedEvent event) {
        System.out.println("Updating inventory for order: " + event.orderId());
    }

    public void onOrderCreatedAsync(@ObservesAsync OrderCreatedEvent event) {
        System.out.println("Async audit log for order: " + event.orderId());
    }
}

Uygulama Yaşam Döngüsü Olayları

Quarkus, uygulama başlatıldığında veya sonlandırıldığında başlatma kodunu yürütmek için başlatma ve kapatma olaylarını kullanıma sunar:

@ApplicationScoped
public class ApplicationLifecycleBean {

    void onStart(@Observes StartupEvent ev) {
        System.out.println("Quarkus Application starting up...");
    }

    void onStop(@Observes ShutdownEvent ev) {
        System.out.println("Quarkus Application shutting down...");
    }
}

8. Instance<T> ve Arc.container() ile Programlı Bean Araması

Hedef uygulamaların çalışma zamanında (veya eski CDI olmayan örnekler içinde) dinamik olarak seçilmesi gerektiğinde, Instance<T> veya Quarkus Arc.container() statik aramayı kullanın.

@ApplicationScoped
public class DynamicPluginRegistry {

    @Inject
    Instance<PaymentProcessor> processors;

    public void executeAll(double amount) {
        for (PaymentProcessor processor : processors) {
            processor.process(amount);
        }
    }
}

9. Mimari Karşılaştırma: Quarkus ArC, Spring IoC ve Weld

Özellik Kuark ArC Bahar IoC Kabı Standart Jakarta Kaynağı
Bağımlılık Çözümü Yapım Süresi (AOT) Çalışma Zamanı Yansıması Çalışma Zamanı Yansıması
Metaspace RAM Yükü Son Derece Düşük (meta veriler için ~0 MB) Yüksek (Dinamik Proxy Sınıfı Önbelleği) Orta ila Yüksek
Başlangıç ​​Zamanı Milisaniye (< 0,05s) Saniye (2,5s - 8s) Saniye (1,5s - 4s)
GraalVM Yerel Desteği Yerli Kullanıma hazır Bahar Yerel İpuçları gerektirir Karmaşık konfigürasyon
Kullanılmayan Fasulye Budama Otomatik Yapım Zamanı Budama Classpath’ta tutuldu Classpath’ta tutuldu
Tek Yapıcı Enjeksiyonu Örtülü (Ek açıklamaya gerek yok) Destekleniyor ‘@Inject’ gerektirir

10. @QuarkusTest ve @InjectMock ile CDI Fasulyelerinin Birim Testi

Quarkus, JUnit 5 ve RestAssured ile CDI çekirdeklerinin test edilmesini sorunsuz hale getiriyor. Bağımlılık fasulyelerini test sırasında otomatik olarak Mockito alaylarıyla değiştirmek için @InjectMock kullanın.

package com.ghaznix;

import com.ghaznix.services.OrderProcessingService;
import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

@QuarkusTest
public class OrderServiceTest {

    @Inject
    OrderService orderService;

    @InjectMock
    OrderProcessingService orderProcessingService;

    @Test
    public void testOrderCheckout() {
        Mockito.when(orderProcessingService.processOrder("ORD-101"))
               .thenReturn("Mocked Success");

        String result = orderService.checkout("ORD-101");
        Assertions.assertEquals("Mocked Success", result);
    }
}

11. Sonuç

Quarkus’ta CDI (ArC) ile Dependency Injection, kurumsal Java tasarımında muazzam bir değişime işaret ediyor. Quarkus, fasulye meta veri taramasını, proxy oluşturmayı ve enjeksiyon grafiği çözünürlüğünü derleme zamanına aktararak süpersonik başlatma hızları, atomik bellek ayak izleri ve kesintisiz GraalVM yerel ikili desteği sunar.

İster Spring Boot’tan geçiş yapın, ister Kubernetes’te sıfırdan bulutta yerel mikro hizmetler oluşturuyor olun, Quarkus CDI’da uzmanlaşmak sizi modern yazılım mimarisi için gereken performans ve geliştirici üretkenliğiyle donatır.

Ghaznix Ecosystem Products

Empower Your Digital Presence & Workflows

Explore top-tier tools built by Ghaznix to streamline your links, surveys, and brand growth.