2013-05-09 16 views
29

Spring'in bağımlılık enjeksiyonunu kullanarak fasulyeleri JPA @Entity'a enjekte etmek mümkün mü?Bir JPA @Entity içinde Bean enjeksiyonu

@Autowire ServletContext'i denedim ancak sunucu başarılı bir şekilde başladığında, bean özelliğine erişmeye çalışırken bir NullPointerException aldım.

@Autowired 
@Transient 
ServletContext servletContext; 
+0

Ben de bir EntityListener içine EntityManager enjekte ederken sorunun aynı tür bakan ve bir çözüm bulundu ve başka yazı http://stackoverflow.com/questions/22171221/how-to-inject-entitymanager-in üzerinde yanıt verdi edildi -entitylisteners/42222592 # 42222592 –

cevap

31

Burada açıklandığı gibi @Configurable kullanarak Bahar konteyner tarafından yönetilmeyen nesnelere içine bağımlılıkları enjekte edebilir http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-atconfigurable.

Şimdiye kadar gerçekleştirdiğiniz gibi, @Configurable ve uygun AspectJ dokuma yapılandırması kullanılmadığı sürece, Spring, new işleci kullanılarak oluşturulan nesnelere bağımlılıklar eklemez. Aslında, varlıkları hakkında bilmediği basit sebepten dolayı, 'dan almadıkça bağımlılıkları nesnelere enjekte etmez. Varlığınızı @Component ile belirtseniz bile, bu varlığın gerçekleştirilmesi, sizin tarafınızdan veya Hazırda Bekletme gibi bir çerçeve tarafından bir new işlemi tarafından gerçekleştirilecektir. Unutmayın, ek açıklamalar yalnızca meta verilerdir: kimse meta verileri yorumlamazsa, herhangi bir davranış eklemez veya çalışan bir program üzerinde herhangi bir etki yaratmaz.

Tüm bunlar söylenirse, bir ServletContext numaralı nesneyi bir nesneye enjekte etmenizi şiddetle tavsiye ederim. Varlıklar, alan modelinizin bir parçasıdır ve Servlet tabanlı bir web yayınlama katmanı gibi herhangi bir dağıtım mekanizmasından ayrıştırılmalıdır. Bir komut satırı istemcisi veya bir ServletContext içermeyen başka bir şey tarafından erişildiğinde bu varlığı nasıl kullanacaksınız? Gerekli verileri ServletContext'ten çıkarmalı ve bunu geleneksel yöntem argümanları aracılığıyla varlığınıza iletmelisiniz. Bu yaklaşımla çok daha iyi bir tasarıma sahip olacaksınız.

+2

Bu soruya verilen yanıtların her ikisi de, kullanışlı bir SO iş parçacığının mükemmel bir örneğidir (her ikisine de ayrılmış). @RaviThapliyal'in yanıtı, sonuca ulaşmanın bir yolunu sağlarken, cevabınız bağlamsal arka plan sağlar (benim için bu bir "aha" idi - geçen haftalarda okudum Spring'in DI hakkında tüm teorik bilgileri dönüştüren bir deneyim oldu. pratik olarak uygulanabilir bilgiye). Imo, SO'da bu tür mesajlar için yeterli olamaz, çünkü onlar aslında bir şey öğretiyorlar (ve çoğu zaman size daha fazla temsilci getirmemek). – sthzg

17

Evet, tabi ki yapabilirsiniz. Ayrıca, öğenin, aynı zamanda, aşağıdaki gibi <bean> etiketlerini (bazı ilkbahar-context.xml'de) kullanarak ya da ek açıklamalarla Spring yönetilen bir fasulye olarak da kaydettirildiğinden emin olmanız gerekir.

Ek açıklamaları kullanarak varlıklarınızı @Component (veya DAO'lar için otomatik istisna çevirisini sağlayan ve JPA ile etkileşime girmeyebilecek şekilde daha özel bir stereotype @Repository) işaretleyebilirsiniz. Eğer varlıklar için size kişiler fasulye gibi yakalandı ve onların bağımlılıkları otomatik kablolu olsun, böylece Bahar tarafından taranan verdikleri paketi (veya bazı atası paketi) yapılandırmanız gerekir Bunu yaptıktan sonra

@Entity 
@Component 
public class MyJAPEntity { 

    @Autowired 
    @Transient 
    ServletContext servletContext; 
    ... 
} 

. ServletContextstatik Yapımı (nihayet çalıştı ne ve neden)

  • :

    <beans ... xmlns:context="..." > 
        ... 
        <context:component-scan base-package="pkg.of.your.jpa.entities" /> 
    <beans> 
    

    DÜZENLEME.

    @Transient 
    private static ServletContext servletContext; 
    

yana, JPA yani Bahar fasulye yönetilen kullanmayan ayrı bir varlık örneği yaratıyor (@Autowired kaldırmak), bu ortak olmak bağlamda için gerekli oluyor.

  • bir @PostConstructinit() ekleme yöntemi. Zaten enjekte değilse

    @PostConstruct 
    public void init() { 
        log.info("Initializing ServletContext as [" + 
           MyJPAEntity.servletContext + "]"); 
    } 
    

Bu Varlık örneği edildikten sonra init() ve iç ServletContext başvurarak ateşler, bu statik mülkiyet enjeksiyon zorlar.

  • bir örneği yönteme @Autowired Hareketli ama içinde statik alanını ayarlama.

    JPA Bahar kabını kullanmaz çünkü ne istediğini yapmanın hiçbir oldukça yolu yok

    :

    @Autowired 
    public void setServletContext(ServletContext servletContext) { 
        MyJPAEntity.servletContext = servletContext; 
    } 
    

biz böyle saçmalıklara istihdam zorunda neden yanıtlamak için aşağıdaki benim son yorumunu aktaran varlıklarını somutlaştırmak için. JPA'yı, varlıkların yaşam döngüsünü başlatan ve yöneten (ilkbahardan tamamen ayrı) ayrı bir ORM konteyneri olarak düşünün ve DI'yi yalnızca varlık ilişkilerine dayalı olarak yapın.

+0

Ne yazık ki, 'servletContext', varlığa' @ Bileşen 'ekledikten sonra hala null ve '' '' app-config.xml'. – theblang

+0

Statikleştirin. 'private static ServletContext servletContext;' Hâlâ '' null' ise, bir '@PostConstruct public void init() {log.info (" ServletContext'i ["+ ​​MyJPAEntity.servletContext +"] "olarak başlatarak; Umuyoruz bu yardımcı olur. –

+0

Bunu 'statik' yaptıktan sonra hala boş. Sanırım, 'PostConstruct' ın ne yaptığına dair kafam karıştı. – theblang

0

sonra beni zarif bir çözümün düşündürdü ben this SO answer rastladım uzun zaman:

  • Bununla bir @Repository DAO olun
  • gereken tüm @Transient @Autowired alanlar kuruluşlara ekle autowired alanı: String beanName = fetchedEntity.getClass().getSimpleName(); autowirer.autowireBean(fetchedEntity); fetchedEntity = (FetchedEntity) autowirer.initializeBean(fetchedEntity, beanName);
: sizin DAO itibaren @Autowired private AutowireCapableBeanFactory autowirer;
  • , DB'den varlık getirilirken sonra bu Autowiring kodunu çağrı

    Varlığınız, sonra otomatik bağlantılı alanlara @Component'ın herhangi biri gibi erişebilecek.