2013-04-15 34 views
7

Tôi đang sử dụng để sử dụng Spring để làm dependency injection tôi như vậy:Sử dụng mô hình Hibernate 4 của tích hợp và dependency injection Spring

<context:component-scan base-package="org.emmerich.myapp" /> 

và sau đó chú thích các lớp học phụ thuộc của tôi với Autowired như vậy:

public class DependentClass { 

    @Autowired 
    private Dependency dependency; 

} 

Tuy nhiên, với những thay đổi trong Hibernate 4.0, chúng tôi hiện khuyên bạn nên sử dụng giao diện Integrator mới để khám phá dịch vụ. Điều này bao gồm việc thêm trình xử lý sự kiện cho các trình kích hoạt như postUpdate, postDelete v.v.

Thật không may, điều này không chơi độc đáo với việc tiêm phụ thuộc thông qua các phụ thuộc có chú thích. Tôi có thiết lập sau:

Trình tích hợp tôi đã xác định để thêm người nghe của mình vào ServiceFactory. Điều này được tham chiếu trong tập tin META-INF/services/org.hibernate.integrator.spi.Integrator.

public class MyIntegrator implements Integrator { 

    private MyListener listener; 

    public MyIntegrator() { 
     listener = new MyListener(); 
    } 

    @Override 
    public void integrate(Configuration configuration, 
          SessionFactoryImplementor sessionFactory, 
          SessionFactoryServiceRegistry serviceRegistry) { 
    final EventListenerRegistry eventRegistry = 
     serviceRegistry.getService(EventListenerRegistry.class); 

    eventRegistry.prependListeners(EventType.POST_COMMIT_INSERT, listener); 

} 

Tôi cũng đã xác định lớp học MyListener, trông giống như người nghe sự kiện điển hình của bạn.

@Component 
public class MyListener implements PostInsertEventListener { 

    @Autowired 
    private Dependent dependent; 

    public void onPostInsert(PostInsertEvent event) { 
     // dependent == null 
    } 

} 

May mắn thay, như được hiển thị trong nhận xét, điều này không hiệu quả. Tôi đoán đó là vì tôi đang instantiating MyListener bên trong MyIntegrator, nó không nhận các thành phần và không autowire thành phần. Tuy nhiên, nếu tôi thử điều này:

@Component 
public class MyIntegrator { 

    @Autowired 
    private MyListener listener; 

    ... 
} 

Sau đó, người nghe không được tự động.

Thứ nhất, cảm thấy sai khi sử dụng Spring phải làm new MyListener(). Tôi mong đợi để có thể xác định rằng như là một phụ thuộc autowired và có mùa xuân tạo ra một singleton cho tôi. Câu hỏi của tôi là:

Cách tiếp cận tốt nhất để sử dụng tiêm phụ thuộc với giao diện Tích hợp mới là gì? Các bộ tích hợp được sử dụng để xây dựng một SessionFactory, và vì vậy khi chúng được yêu cầu tích hợp chúng, tôi đoán không có một ngữ cảnh ứng dụng có sẵn. Do đó, bất kỳ hạt cà phê nào tôi yêu cầu trong Trình tích hợp cần được tạo theo cách "cũ kỹ" và sẽ không nhận được sự tự động trên chúng.

Tôi khá mới với thế giới của mùa xuân, bạn có nói đây là điều mà tôi nên trông đợi không? Tôi hiểu rằng tôi đang ở trong một phạm vi khác nhau của ứng dụng khi tôi đang trong SessionFactory, nhưng có cách nào để có được một tham chiếu đến đậu và cho phép autowire mặc dù tôi đang tạo nó qua new?

Giải pháp tôi đã sử dụng ApplicationContextAware. Nó có nghĩa là MyListener nhận được một tham chiếu đến ApplicationContext bất cứ khi nào bối cảnh có sẵn, và tôi đã tham chiếu các bean từ ngữ cảnh trên các cuộc gọi phương thức, thay vì xây dựng bean. Tạo một hạt đậu với new không giới hạn điều này, do đó, Spring vẫn cung cấp cho tôi ngữ cảnh ứng dụng:

@Component 
public class MyListener implements PostInsertEventListener, ApplicationContextAware { 

    private static ApplicationContext context; 

    public void onPostInsert(PostInsertEvent event) { 
     // getDependent() == correct! 
    } 

    public void setApplicationContext(ApplicationContext context) throws BeanException { 
     this.context = context; 
    } 

    public Dependent getDependent() { 
     return context.getBean(Dependent.class); 
    } 

} 

Có cách nào tốt hơn không?

+0

Bạn không quên thành phần quét 'MyIntegrator 'lớp trong ví dụ' @ Autowired' của bạn? Ngoài ra, ai đang khởi tạo lớp 'MyIntegrator'? –

+0

Đây chính xác là giải pháp mà tôi đã đưa ra. Của nó làm việc tốt đẹp nhưng các appcontext tĩnh chỉ cảm thấy một chút bẩn :) tôi chỉ không tìm thấy một cách đẹp hơn kể từ khi ngủ đông là tạo ra các Integrator. Một khi tôi sẽ có thời gian tôi muốn làm cho điều này trừu tượng hơn và có một tích hợp mà chỉ là một liên kết để có thể đăng ký người nghe, vv được tạo ra bởi mùa xuân. Tôi đã tìm thấy một blog nhưng tôi không thể nhớ được url ngay bây giờ. –

+1

@SotiriosDelimanolis Hibernate tạo 'Integrator' cho bạn. Bạn chỉ định một tệp văn bản trong thư mục 'META-INF/services' của bạn trỏ đến danh sách các trình tích hợp bạn muốn khởi tạo và Hibernate xây dựng chúng cho bạn trước khi tạo SessionFactory. Tôi hiểu rằng không thể sử dụng các thành phần Autowire trong Trình tích hợp - nó được xây dựng bên ngoài phạm vi của ứng dụng. Tuy nhiên, tôi nghĩ rằng có thể sử dụng @Autowired trong trình nghe. Và có, tôi là bối cảnh quét tất cả các lớp học liên quan. – EMMERICH

Trả lời

12

Như đã nêu trong nhận xét tôi đã đi một cách khác để tích hợp Spring được quản lý HibernateEventListeners.Dưới đây là các mã:

Giao diện định danh cho mùa xuân quản lý Hibernate nghe sự kiện:

public interface HibernateEventListener { } 

Các HibernateIntegrator:

@Service 
public class HibernateSpringIntegrator { 

    private static final Logger log = LoggerFactory.getLogger(HibernateSpringIntegrator.class); 

    @Autowired 
    private HibernateEntityManagerFactory entityManagerFactory; 

    @Autowired 
    private HibernateSpringIntegratorRegistry hibernateSpringIntegratorRegistry; 

    @PostConstruct 
    public void registerListeners() { 
     log.debug("Registering Spring managed HibernateEventListeners"); 

     EventListenerRegistry listenerRegistry = ((SessionFactoryImpl) entityManagerFactory 
       .getSessionFactory()).getServiceRegistry().getService(
       EventListenerRegistry.class); 
     List<HibernateEventListener> eventListeners = hibernateSpringIntegratorRegistry 
       .getHibernateEventListeners(); 
     for (HibernateEventListener hel : eventListeners) { 
      log.debug("Registering: {}", hel.getClass()); 
      if (PreInsertEventListener.class.isAssignableFrom(hel.getClass())) { 
       listenerRegistry.appendListeners(EventType.PRE_INSERT, 
         (PreInsertEventListener) hel); 
      } 
      if (PreUpdateEventListener.class.isAssignableFrom(hel.getClass())) { 
       listenerRegistry.appendListeners(EventType.PRE_UPDATE, 
         (PreUpdateEventListener) hel); 
      } 
      if (PreDeleteEventListener.class.isAssignableFrom(hel.getClass())) { 
       listenerRegistry.appendListeners(EventType.PRE_DELETE, 
         (PreDeleteEventListener) hel); 
      } 
      if (PostInsertEventListener.class.isAssignableFrom(hel.getClass())) { 
       listenerRegistry.appendListeners(EventType.POST_INSERT, 
         (PostInsertEventListener) hel); 
      } 
      if (PostUpdateEventListener.class.isAssignableFrom(hel.getClass())) { 
       listenerRegistry.appendListeners(EventType.POST_UPDATE, 
         (PostUpdateEventListener) hel); 
      } 
      if (PostDeleteEventListener.class.isAssignableFrom(hel.getClass())) { 
       listenerRegistry.appendListeners(EventType.POST_DELETE, 
         (PostDeleteEventListener) hel); 
      } 
      // Currently we do not need other types of eventListeners. Else this method needs to be extended. 
     } 
    } 
} 

Các "Registry":

@Component 
public class HibernateSpringIntegratorRegistry { 

    @Autowired(required = false) 
    private List<HibernateEventListener> hibernateEventListeners; 

    public List<HibernateEventListener> getHibernateEventListeners() { 
     if (hibernateEventListeners == null) { 
      return Collections.emptyList(); 
     } 
     return hibernateEventListeners; 
    } 
} 

Và đây là một triển khai ví dụ:

@Component 
public class MailGenerationEventListener implements HibernateEventListener, 
    PostDeleteEventListener, PostInsertEventListener, PostUpdateEventListener { 

    @Override 
    public void onPostDelete(PostDeleteEvent event) { 
     Class<?> entityClass = event.getEntity().getClass(); 
     ... 
    } 

    @Override 
    public void onPostInsert(PostInsertEvent event) { 
     Class<?> entityClass = event.getEntity().getClass(); 
     ... 
    } 

    @Override 
    public void onPostUpdate(PostUpdateEvent event) { 
     Class<?> entityClass = event.getEntity().getClass(); 
     ... 
    } 
} 
+0

Câu trả lời thú vị. Đây có phải là phương án thay thế cho việc triển khai giao diện 'Tích hợp' và xác định tệp văn bản tích hợp trong' META-INF/services' không? – EMMERICH

+0

Tôi đoán vấn đề tôi có với điều này là nó không tuân theo mẫu Trình tích hợp, thay vào đó nó cung cấp một cách tùy chỉnh Springified để đính kèm các trình lắng nghe sự kiện. – EMMERICH

+0

Có điều này là hoàn thành Springifed thực hiện. Tôi nghĩ rằng người ta có thể đi theo cách thực hiện HibernateSpringIntegrator như một dịch vụ tích hợp "thực" bằng cách sử dụng ApplicationContextAware và tìm nạp HibernateSpringIntegratorRegistry. Bằng cách này, trình tích hợp là Hibernate giống như tham chiếu ứng dụng tĩnh nhưng vẫn có thể sử dụng tính năng tự động đơn giản cho các danh sách sự kiện thông qua đăng ký –

-1

Trong một bản nâng cấp từ chế độ ngủ đông 3,6-4,2, chúng tôi cần phải có một validator tùy chỉnh mà sử dụng đậu mùa xuân được quản lý bằng cách thực hiện cấu hình sau:

<!-- Make our validators use DI if necessary --> 
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/> 

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
    <!-- other props --> 
    <property name="hibernateProperties"> 
      <map> 
       <entry key="javax.persistence.validation.factory" value-ref="validator" /> 
      </map> 
    </property> 
</bean> 
+0

Làm thế nào điều này có liên quan? –

Các vấn đề liên quan