2012-04-02 16 views
6

Mùa xuân có cơ chế tốt đẹp PropertyPlaceholderConfigurer để chèn các giá trị như timeouts, Url JDBC và vân vân vào Spring bean cho mục đích cấu hình. Có cách nào hợp lý để xử lý các giá trị cấu hình có thể thay đổi khi chạy không?Mùa xuân: làm thế nào để thực hiện cấu hình thuộc tính có thể thay đổi trong thời gian chạy trong suốt

CẬP NHẬT: Với Spring 3.1, có một cách hay để bao gồm các nguồn cấu hình không tĩnh chẳng hạn như cơ sở dữ liệu qua PropertySource s. Một số ApplicationContexts cung cấp một cơ chế làm mới về nguyên tắc có thể xử lý các giá trị cấu hình thay đổi. Tuy nhiên, nó dừng ứng dụng trước, sau đó tạo tất cả các bean mới và sau đó bắt đầu lại bối cảnh ứng dụng. Tuy nhiên, với mục đích của chúng tôi, tôi sẽ cần một cách để làm điều này một cách minh bạch, sao cho máy chủ xử lý chính xác các yêu cầu hiện đang chạy.

Một ý tưởng khác để thực hiện việc này sẽ là Phạm vi tùy chỉnh tạo đối tượng mới khi thay đổi cấu hình. Thật không may là ObjectFactory cung cấp cho Scope sử dụng định nghĩa bean đã được xử lý trước, sao cho các placeholders không được đọc một lần nữa từ cấu hình. Vì vậy, các đối tượng được tạo có cùng cấu hình. :-(

+0

Có lẽ một cách để làm điều đó là sử dụng PropertyOverrideConfigurer http://stackoverflow.com/a/595201/21499, nhưng tôi nghĩ rằng cơ chế ghi đè thuộc tính khá khó xử khi sử dụng và dễ bị lỗi. –

Trả lời

2

Sau đây là một chút kỳ quặc nhưng hoạt động. Bạn tạo một custom scope có tên là reconfigurable để ném tất cả các hạt được tạo ra trong phạm vi đó bất cứ khi nào cập nhật cấu hình xảy ra. Do đó, một bean mới sẽ được tạo sau khi thay đổi cấu hình.

Giá trị cấu hình thực tế phải được truy lục thông qua ngôn ngữ biểu thức mùa xuân vì các giá trị cho cả cú pháp $ {} bình thường cũng như PropertyOverrideConfigurer dường như cố định vĩnh viễn trong BeanDefinition. Một tuyên bố đậu cho một bean với một tái cấu hình bất động sản someProperty trông như thế này:

<bean class="blablu.Testbean" scope="reconfigurable" 
    p:someProperty="#{ config['configexplicit']}"> 
    <aop:scoped-proxy /> 
</bean> 

Bạn cần phải sử dụng AOP: scoped-proxy mà đậu sử dụng đậu này luôn lấy đậu cấu hình tươi từ phạm vi tùy chỉnh .

Khai báo các thuộc tính với @Value cũng hoạt động; nếu bạn sử dụng quét thành phần bạn cần phải khai báo phạm vi với chú thích

@Scope(value="reconfigurableScope", proxyMode=ScopedProxyMode.TARGET_CLASS) 

Nếu bạn quan tâm để biết chi tiết: ý tưởng cơ bản về phạm vi là:

public class ReconfigurableScope implements Scope { 

    private final Map<String, Object> nameToObjectMap = new ConcurrentHashMap<String, Object>(); 

    public Object get(final String name, final ObjectFactory<?> objectFactory) { 
     Object bean = nameToObjectMap.get(name); 
     if (null == bean) { 
      bean = objectFactory.getObject(); 
      nameToObjectMap.put(name, bean); 
     } 
     return bean; 
    } 

    // called from outside on each configuration change 
    public void update(final ConfigurationObservable observable, final Object arg) { 
     nameToObjectMap.clear(); 
    } 

} 

Ngoài ra một số công cụ an toàn thread và dọn dẹp: các hạt đã loại bỏ cần phải được hủy bỏ một chút sau đó và trên bối cảnh ứng dụng gần.

+0

Bất kỳ mẫu mã nguồn nào của phạm vi tùy chỉnh của bạn đều có thể? :) – Kakawait

2

Đáng tiếc là cấu hình từ properties file là tĩnh và xảy ra lúc khởi động Những gì tôi thường làm là phơi bày các thuộc tính động thông qua :.

@ManagedResource 
@Service 
public class BusinessService { 

    @ManagedAttribute 
    private int age; 

    public int getAge() { 
     return age; 
    } 

    public void setAge(int age) { 
     this.age = age; 
    } 

    public void businessMethod() { 
     //use age... 
    } 

} 

Hãy nhớ thêm:

<context:mbean-export/> 

Để Bây giờ bạn có thể truy cập và thay đổi thuộc tính đó qua jconsole hoặc bất kỳ ứng dụng khách JMX nào khác.Xem thêm: 23.3.2 Using Source-Level Metadata (JDK 5.0 annotations).

+0

Các tệp thuộc tính không nhất thiết phải tĩnh - chúng có thể nằm ở đâu đó trong hệ thống tệp và được thay đổi bằng các op. Bạn nói đúng: người ta có thể sử dụng các cơ chế khác để cập nhật các giá trị cấu hình, nhưng tôi muốn sử dụng cơ chế giữ chỗ mùa xuân tốt đẹp. Nếu không - làm thế nào bạn sẽ cập nhật, nói, một thời gian chờ cho một WebserviceTemplate mà không có nhiều mã keo? –

+0

@hstoerr: wrt 'WebserviceTemplate' - nó đòi hỏi một số mã keo ngay cả khi bạn không cần phải làm mới bất cứ điều gì: http://onebyteatatime.wordpress.com/2009/03/19/how-to-set-socket-timeout -using-spring-webservicetemplate/và http://stackoverflow.com/questions/6733744 –

0

Để cấu hình lại thời gian chạy hiệu quả, bạn có thể sử dụng dự án Cloud Config của mùa xuân. Trong sắp xếp này, bạn sẽ có một Configuration Repository, giả sử một kho lưu trữ git, chứa các giá trị cấu hình của bạn. Sau đó đặt Configuration Server trước kho lưu trữ đó. Máy chủ này sẽ được cập nhật bất cứ khi nào một sự cố xảy ra với kho lưu trữ sao lưu.Cuối cùng, các ứng dụng của bạn sẽ là các máy khách của Config Server và kéo các cấu hình mới từ nó. Kiểm tra Spring Cloud để biết thêm chi tiết.

1

Có một ví dụ chạy của những gì bạn đang cố gắng để hoàn thành ở đây: https://github.com/ldojo/spring-cloud-config-examples

Nó thể hiện như thế nào một máy chủ mùa xuân đám mây Config và dịch vụ khách hàng có thể giao tiếp qua mùa xuân đám mây Bus, và thuộc tính cấu hình của khách hàng có thể thay đổi lúc chạy khi có thay đổi cấu hình trong repo của Config Server.

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