2011-10-11 31 views
8

Tôi có một ứng dụng Java EE + Spring hỗ trợ các chú thích trên cấu hình XML. Các hạt cà phê luôn có phạm vi nguyên mẫu.Tự động xác định bean nào sẽ tự động trong Spring (sử dụng vòng loại)

Tôi hiện có các quy tắc kinh doanh ứng dụng của mình phụ thuộc vào quốc gia mà yêu cầu của người dùng được tạo từ đó. Vì vậy, tôi sẽ có một cái gì đó như thế này (lưu ý ví dụ này là nặng nề đơn giản):

@Component 
public class TransactionService { 
    @Autowired 
    private TransactionRules rules; 
    //.. 
} 


@Component 
@Qualifier("US") 
public class TransactionRulesForUS implements TransactionRules { 
    //.. 
} 

@Component 
@Qualifier("CANADA") 
public class TransactionRulesForCanada implements TransactionRules { 
    //.. 
} 

tôi đang tìm kiếm một cách để làm cho cơ chế tự động hệ thống dây điện tự động tiêm đậu bên phải (hoặc Mỹ hoặc Canada, trong ví dụ này) dựa trên quốc gia của yêu cầu hiện tại. Đất nước sẽ được lưu trữ trong một biến ThreadLocal, và nó sẽ thay đổi trong mỗi yêu cầu. Cũng sẽ có một lớp học toàn cầu, cho tất cả các quốc gia không có quy tắc cụ thể của riêng họ.

Tôi tưởng tượng mình sẽ phải tùy chỉnh cách Spring quyết định cách tạo đối tượng mà nó sẽ tiêm. Cách duy nhất tôi tìm thấy để làm điều này đã được sử dụng FactoryBean, nhưng đó không phải là khá những gì tôi hy vọng (không đủ chung). Tôi đã hy vọng làm điều gì đó như thế này:

  1. Trước khi Spring khởi tạo một đối tượng, mã tùy chỉnh của riêng tôi sẽ phải được gọi.
  2. Nếu tôi phát hiện thấy giao diện được yêu cầu có nhiều triển khai, tôi sẽ tra cứu biến ThreadLocal của mình ở đúng quốc gia và tự động thêm Trình độ chất lượng thích hợp vào yêu cầu tự động dây.
  3. Sau đó, Spring sẽ thực hiện tất cả phép thuật thông thường của nó. Nếu một vòng loại được thêm vào, điều đó sẽ phải được xem xét; nếu không, luồng sẽ tiến hành như bình thường.

Tôi có đi đúng hướng không? Bất kỳ ý tưởng cho tôi về điều này?

Cảm ơn.

Trả lời

0

Bạn có thể cung cấp lớp Cấu hình sẽ trả về đúng bean dựa trên giá trị ThreadLocal. Điều này giả định bạn đang sử dụng Spring 3. Tôi đã làm một bài kiểm tra nhỏ để đảm bảo rằng phương thức nhà cung cấp được gọi trên mỗi yêu cầu. Đây là những gì tôi đã làm.

@Configuration 
public class ApplicationConfiguration 
{ 
    private static int counter = 0; 

    @Bean(name="joel") 
    @Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS) 
    List<String> getJoel() 
    { 
     return Arrays.asList(new String[] { "Joel " + counter++ }); 
    } 
} 

Và tham chiếu giá trị trong Bộ điều khiển của tôi như sau.

@Resource(name="joel") 
private List<String> joel; 

trong việc triển khai nhà cung cấp, bạn có thể kiểm tra ThreadLocal cho ngôn ngữ và trả lại đối tượng TransactionRules chính xác hoặc tương tự như vậy. Các công cụ ScopedProxy là vì tôi đã được tiêm vào một Controller, được Singleton scoped trong khi giá trị là yêu cầu scoped.

4

Tạo chú thích của riêng bạn được sử dụng để trang trí các biến mẫu hoặc phương thức setter, sau đó một bộ xử lý hậu xử lý chú thích và tiêm một proxy chung để giải quyết việc triển khai chính xác khi chạy và ủy quyền cuộc gọi.

@Component 
public class TransactionService { 
    @LocalizedResource 
    private TransactionRules rules; 
    //.. 
} 

@Retention(RUNTIME) 
@Target({FIELD, METHOD}) 
public @interface LocalizedResource {} 

Dưới đây là các thuật toán cho postProcessBeforeInitialization(bean, beanName) phương pháp trong đậu sau xử lý của bạn:

  1. nội quan lớp bean để tìm ra các biến dụ hoặc các phương pháp setter được chú thích với @LocalizedResource. Lưu trữ kết quả trong bộ nhớ đệm (chỉ một bản đồ) được lập chỉ mục theo tên lớp. Bạn có thể sử dụng số InjectionMetadata của Spring cho mục đích này.Bạn có thể tìm các ví dụ về cách nó hoạt động bằng cách tìm kiếm các tham chiếu đến classe này trong mã mùa xuân.
  2. Nếu trường hoặc phương thức như vậy tồn tại đối với bean, hãy tạo proxy bằng cách sử dụng InvocationHandler được mô tả bên dưới, chuyển nó qua BeanFactory hiện tại (trình xử lý hậu đậu phải là ApplicationContextAware). Tiêm proxy đó trong biến cá thể, hoặc gọi phương thức setter với cá thể proxy.

Đây là InvocationHandler cho proxy sẽ được sử dụng để tạo tài nguyên được bản địa hóa.

public class LocalizedResourceResolver implements InvocationHandler { 
    private final BeanFactory bf; 
    public LocalizedResourceResolver(BeanFactory bf) { 
    this.bf = bf; 
    } 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
    String locale = lookupCurrentLocale(); 
    Object target = lookupTarget(locale); 
    return method.invoke(target, args); 
    } 

    private String lookupCurrentLocale() { 
    // here comes your stuff to look up the current locale 
    // probably set in a thread-local variable 
    } 

    private Object lookupTarget(String locale) { 
    // use the locale to match a qualifier attached to a bean that you lookup using the BeanFactory. 
    // That bean is the target 
    } 
} 

Bạn có thể cần thực hiện thêm một số điều khiển đối với loại bean hoặc thêm loại bean được yêu cầu trong InvocationHandler.

Điều tiếp theo là tự động phát hiện các giao diện đã cho, phụ thuộc vào địa phương và đăng ký chúng với bộ định danh tương ứng với ngôn ngữ. Bạn có thể triển khai BeanDefinitionRegistryPostProcessor hoặc BeanFactoryPostProcessor cho mục đích đó, để thêm BeanDefinition s mới vào sổ đăng ký, với trình độ đủ điều kiện, một cho mỗi triển khai giao diện nhận thức miền địa phương. Bạn có thể đoán miền địa phương của một triển khai bằng cách làm theo các quy ước đặt tên: nếu một giao diện nhận biết miền địa phương được gọi là TransactionRules, thì việc triển khai có thể được đặt tên là TransactionRules_ISOCODE trong cùng một gói.

Nếu bạn không có khả năng đặt tên quy ước, bạn sẽ cần phải có một số loại quét đường dẫn + một cách để đoán miền địa phương của một triển khai nhất định (có thể là chú thích trên lớp triển khai). Quét Classpath là có thể nhưng khá phức tạp và chậm, vì vậy hãy thử để tránh nó.

Dưới đây là một bản tóm tắt về những gì sẽ xảy ra:

  1. Khi ứng dụng khởi động, triển khai các TransactionRules sẽ được phát hiện và định nghĩa bean sẽ được tạo cho mỗi người trong số họ, với khuôn khổ vòng loại tương ứng với miền địa phương của mỗi thực hiện . Tên đậu cho những hạt cà phê này không có liên quan như tra cứu được thực hiện dựa trên loại và vòng loại.
  2. Trong khi thực thi, hãy đặt ngôn ngữ hiện tại trong biến địa chỉ
  3. Tra cứu bean bạn cần (ví dụ: TransactionService). Post-processor sẽ tiêm một proxy cho mỗi trường instance @LocalizedResource hoặc phương thức setter.
  4. Khi gọi phương thức trên TransactionService kết thúc thành một số phương thức TransactionRules, trình xử lý yêu cầu được liên kết với proxy chuyển sang triển khai chính xác dựa trên giá trị được lưu trữ trong biến thread-local, sau đó ủy quyền cuộc gọi đến thực hiện đó.

Không thực sự nhỏ, nhưng nó hoạt động. Đây thực sự là cách @PersistenceContext được xử lý bởi Spring, ngoại trừ việc tra cứu triển khai, đây là một tính năng bổ sung của trường hợp sử dụng của bạn.

+1

Bây giờ trong năm 2017, không có cách nào đơn giản hơn để đạt được điều này? – maxxyme

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