2011-06-22 26 views
12

Cách chính xác để sử dụng các hạt của nhà máy ở các lớp @Configuration là gì?Mùa xuân - sử dụng các hạt của nhà máy trong cấu hình?

Giả sử tôi có sau đây cho SessionFactory:

@Bean 
public AnnotationSessionFactoryBean sessionFactory() { 
    AnnotationSessionFactoryBean factory = new AnnotationSessionFactoryBean(); 
    // set up properties etc. 
    return factory; 
} 

Ngay bây giờ phương pháp này trả về một bean factory mà không thực hiện SessionFactory. Nếu tôi sử dụng nó trong một hạt đậu với @Autowired như SessionFactory, nó hoạt động tốt và có được nó từ bean factory:

@Controller 
public class MyController { 
    @Autowired SessionFactory sessionFactory; 
    // ... 
} 

Tôi đoán đó là OK.

Tuy nhiên, nó sẽ trở thành một vấn đề nếu tôi muốn sử dụng SessionFactory trong lớp cấu hình giống nhau:

@Bean 
public HibernateTransactionManager transactionManager() { 
    HibernateTransactionManager man = new HibernateTransactionManager(); 
    // Ideal - doesn't work because sessionFactory() return type doesn't match: 
    // SessionFactory sessionFactory = sessionFactory(); 
    // Is this one correct? 
    // SessionFactory sessionFactory = (SessionFactory) sessionFactory().getObject(); 
    man.setSessionFactory(sessionFactory); 
    return man; 
} 

The Right Way để thực hiện hình thức này phụ thuộc là gì?

Trả lời

20

@Configuration cách tiếp cận vẫn còn tương đối mới và có một số cạnh thô. Hạt đậu là một trong số đó. Vì vậy, không phải là Right Way, ít nhất tôi không biết bất kỳ điều gì. Có lẽ các bản phát hành mùa xuân trong tương lai sẽ xử lý trường hợp này bằng cách nào đó. Hiện tại, đây là cách ưa thích của tôi:

@Bean 
public AnnotationSessionFactoryBean sessionFactoryBean() { 
    AnnotationSessionFactoryBean factory = new AnnotationSessionFactoryBean(); 
    // set up properties etc. 
    return factory; 
} 

@Bean 
public SessionFactory sessionFactory() { 
    return (SessionFactory) sessionFactoryBean().getObject(); 
} 

Và sử dụng phương pháp sessionFactory() bất cứ khi nào cần. Nếu bạn muốn gọi tới số sessionFactoryBean().getObject() nhiều lần vì một số lý do (ví dụ: khi FactoryBean không trả lại số đơn), hãy nhớ sử dụng chú thích @Scope. Nếu không Spring sẽ đảm bảo sessionFactory() chỉ được gọi một lần và lưu vào bộ nhớ cache kết quả.

Mùa xuân đủ thông minh để thực hiện tất cả yêu cầu khởi tạo sau khi gọi phương thức @Bean và trước khi trả lại chính bean. Vì vậy, InitializingBean, DisposableBean, @PostConstruct, v.v ... đều được công nhận và xử lý đúng cách. Trong thực tế, tôi luôn tìm cách gọi afterPropertiesSet một chút của một hack, bởi vì nó là trách nhiệm của container.


Cũng có một phương pháp thứ hai khuyên trong Spring Datastore Document - Reference Documentation, mà ngay từ cái nhìn đầu tiên trông hơi mâu thuẫn, nhưng các công trình lớn:

@Resource 
private Mongo mongo; 

@Bean 
MongoFactoryBean mongo() { 
    return new MongoFactoryBean(); 
} 

Vì vậy, nhà máy được tạo ra sử dụng @Bean phương pháp nhưng đậu được tạo ra bởi nhà máy có thể thu được bằng cách sử dụng lĩnh vực autowired. Tài giỏi.

+0

Không nó đòi hỏi afterPropertiesSet()? –

+0

Không, Mùa xuân đủ thông minh để thực hiện tất cả các yêu cầu khởi tạo sau khi gọi phương thức '@ Bean' và trước khi trả lại chính bean. Vì vậy, 'InitializingBean',' DisposableBean', '@ PostConstruct', vv đều được nhận diện và xử lý đúng cách. Trong thực tế, tôi luôn tìm cách gọi 'afterPropertiesSet' một chút hack, bởi vì nó là trách nhiệm của container. –

+1

Ngoài ra, xem chỉnh sửa của tôi, tôi đã tìm thấy một giải pháp khác. –

0

Tôi đã tìm thấy ví dụ về điều này trên Spring forums.

@Bean 
public SessionFactory sessionFactory() { 
    AnnotationSessionFactoryBean sessionFactoryBean = 
       new AnnotationSessionFactoryBean(); 
    // ...configuration code here... 
    sessionFactoryBean.afterPropertiesSet(); 
    return sessionFactoryBean.getObject(); 
} 
+2

Đó là một ý tưởng tồi. Nếu bạn làm điều này, vòng đời của 'FactoryBean' sẽ không được quản lý như nó cần, và ứng dụng của bạn sẽ không tắt sạch. Trong ví dụ cụ thể này, bạn có thể tránh vấn đề bằng cách sử dụng '@Bean (destroyMethod =" close ")', nhưng nó không tuyệt vời. – skaffman

0

Bạn có thể sử dụng nó theo cách sau:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration 
public class LoginServiceTest { 

    @Configuration 
    public static class Config { 

    @Bean 
    public HttpInvokerProxyFactoryBean loginServiceProxy() { 
     HttpInvokerProxyFactoryBean proxy = new HttpInvokerProxyFactoryBean(); 
     proxy.setServiceInterface(LoginService.class); 
     proxy.setServiceUrl("http://localhost:8080/loginService"); 
     return proxy; 
    } 

    } 

    @Inject 
    private LoginService loginService; 

    @Test 
    public void testlogin() { 
    loginService.login(...); 
    } 
} 
Các vấn đề liên quan