Neden @PostConstruct kullanıyorsunuz?


295

Yönetilen bir çekirdekte, @PostConstructdüzenli Java nesne oluşturucusundan sonra çağrılır.

Neden @PostConstructnormal kurucu yerine fasulye ile başlangıç ​​yapmak için kullanayım?


4
Bağımlılık yapılmasına izin vermek için genellikle yapıcı enjeksiyonunun tercih edildiği izlenimini edindim final. Bu model göz önüne alındığında, neden @PostConstructJ2EE'ye ekleniyor - mutlaka başka bir kullanım durumu görmüş olmalılar?
mjaggard

Yanıtlar:


410
  • çünkü kurucu çağrıldığında, fasulye henüz başlatılmamıştır - yani hiçbir bağımlılık enjekte edilmemiştir. Gelen @PostConstructyöntemle fasulye tam olarak başlatılmadan ve bağımlılıkları kullanabilirsiniz.

  • çünkü bu, bu yöntemin fasulye yaşam döngüsünde sadece bir kez uygulanmasını garanti eden bir sözleşmedir. Bir çekirdeğin, iç işleyişinde kap tarafından birden çok kez başlatılması (olası olmasa da) olabilir, ancak @PostConstructyalnızca bir kez çağrılmasını garanti eder .


17
kurucunun kendisinin tüm bağımlılıkları otomatik olarak kablolaması durumunda - çekirdek de yapıcıda tamamen başlatılabilir (tüm otomatik kablolu alanları manuel olarak ayarladıktan sonra).
yair

7
bir fasulyenin yapıcısına bir kereden fazla çağrılabilecek durum nedir?
yair

1
Muhtemelen "pasivasyon" gibi bir şey. Konteyner fasulyeyi disk deposunda saklamaya karar verirse ve oradan geri yükler.
Bozho

13
Yapıcıyı defalarca çağırdı görmek pek mümkün değil. Kap bir proxy başlattığında, kurucunun proxy için en az bir kez ve gerçek fasulye için bir kez çağrıldığını göreceksiniz.
marcus

Not @PostConstruct yöntemleri olduğunu değil sayfa sunucu yeniden hemen sonra yüklendiğinde denir. (Bu bir JBoss hatası olabilir.)
Dave Jarvis

96

Ana sorun şudur:

bir kurucuda, bağımlılıkların enjeksiyonu henüz gerçekleşmemiştir *

* Konstrüktör Enjeksiyonu hariç


Gerçek dünya örneği:

public class Foo {

    @Inject
    Logger LOG;

    @PostConstruct
    public void fooInit(){
        LOG.info("This will be printed; LOG has already been injected");
    }

    public Foo() {
        LOG.info("This will NOT be printed, LOG is still null");
        // NullPointerException will be thrown here
    }
}

ÖNEMLİ : @PostConstructve @PreDestroy tamamen edilmiş Java 11'de çıkarıldı .

Bunları kullanmaya devam etmek için bağımlılıklarınıza javax.annotation-api JAR eklemeniz gerekir .

Uzman

<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

Gradle

// https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api
compile group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'

19
in a constructor, the injection of the dependencies has not yet occurred. ayarlayıcı veya alan enjeksiyonuyla doğru, ancak yapıcı enjeksiyonuyla doğru değil.
Adam Siemion

@PostConstruct'ın Java 11'de kaldırılmasıyla, artık Java 11 ile bu gerçek dünya örneğini nasıl ele alabiliriz?
tet

@tet Yanıtta belirtildiği gibi, javax.annotation-api kütüphanesini kullanmanız gerekir. Bu ek açıklamalar Java 11'de kaldırıldı, ancak Java 9'dan beri kullanımdan kaldırıldı olarak işaretlendi
narendra-choudhary

63

Sınıfınız tüm başlatmasını yapıcıda gerçekleştirirse, @PostConstructgerçekten gereksizdir.

Ancak, sınıfınızın bağımlılıkları ayarlayıcı yöntemleri kullanılarak enjekte edilmişse, sınıfın yapıcısı nesneyi tam olarak başlatamaz ve bazen tüm ayarlayıcı yöntemleri çağrıldıktan sonra bazı başlatma işlemlerinin gerçekleştirilmesi gerekir @PostConstruct.


@staffman: artı bir yanımdan. Ben bir girdi metin alanı veritabanından getirilen bir değerle başlatmak istiyorsanız, ben PostConstruct yardımı ile bunu başardık, ama aynı yapıcı içinde yapmaya çalıştığınızda başarısız olur. PostContruct kullanmadan başlatmak için bu gereksinim var. Zamanınız varsa, lütfen buna da cevap verebilir misiniz: stackoverflow.com/questions/27540573/…
Shirgill Farhan

10

Aşağıdaki senaryoyu düşünün:

public class Car {
  @Inject
  private Engine engine;  

  public Car() {
    engine.initialize();  
  }
  ...
}

Otomobilin saha enjeksiyonundan önce başlatılması gerektiğinden, enjeksiyon noktası motoru yapıcı yürütülürken hala boştur ve sonuçta NullPointerException oluşur.

Bu sorun, Java yapıcı enjeksiyonu için JSR-330 Bağımlılık Enjeksiyonu veya Java @PostConstruct yöntemi ek açıklaması için JSR 250 Ortak Ek Açıklamaları ile çözülebilir .

@PostConstruct

JSR-250, Java SE 6'da bulunan yaygın bir ek açıklama kümesini tanımlar.

PostConstruct ek açıklaması, herhangi bir başlatma gerçekleştirmek için bağımlılık enjeksiyonu yapıldıktan sonra yürütülmesi gereken bir yöntemde kullanılır. Sınıf kullanılmadan önce bu yöntem çağrılmalıdır ZORUNLU. Bu açıklama bağımlılık enjeksiyonunu destekleyen tüm sınıflarda desteklenmelidir ZORUNLU.

JSR-250 Bölüm. 2.5 javax.nono.PostConstruct

@PostConstruct ek açıklaması, örnek başlatıldıktan ve tüm enjeksiyonlar gerçekleştirildikten sonra yürütülecek yöntemlerin tanımına izin verir.

public class Car {
  @Inject
  private Engine engine;  

  @PostConstruct
  public void postConstruct() {
    engine.initialize();  
  }
  ...
} 

Yapıcıda başlatmayı gerçekleştirmek yerine, kod @PostConstruct ile açıklamalı bir yönteme taşınır.

İnşaat sonrası yöntemlerin işlenmesi, @PostConstruct ile açıklamalı tüm yöntemleri bulmak ve bunları sırayla çağırmak için basit bir konudur.

private  void processPostConstruct(Class type, T targetInstance) {
  Method[] declaredMethods = type.getDeclaredMethods();

  Arrays.stream(declaredMethods)
      .filter(method -> method.getAnnotation(PostConstruct.class) != null) 
      .forEach(postConstructMethod -> {
         try {
           postConstructMethod.setAccessible(true);
           postConstructMethod.invoke(targetInstance, new Object[]{});
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {      
          throw new RuntimeException(ex);
        }
      });
}

Yapım sonrası yöntemlerin işlenmesi, örnekleme ve enjeksiyon tamamlandıktan sonra gerçekleştirilmelidir.


1

Ayrıca, kurucu tabanlı başlatma, bir tür proxy veya uzaklaştırma söz konusu olduğunda amaçlandığı gibi çalışmaz.

Bir EJB'nin serisini kaldırıldığında ve bunun için yeni bir proxy oluşturulduğunda ct çağrılır ...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.