2016-08-22 20 views
6

Tôi có một dự án với một số độc lập đậu X, đó là autowired trong một loạt các dịch vụ. Các dịch vụ được sử dụng bởi nhau và cuối cùng được sử dụng trong một điểm vào (bộ điều khiển). Bây giờ có yêu cầu mới: thực hiện một số phiên bản của X, và quyết định một phù thủy là sử dụng theo tham số của điểm nhập cảnh (enum XType). Nó sẽ được tốt đẹp để làm điều đó mà không thay đổi dịch vụ.Autowiring hoàn toàn đủ điều kiện trong mùa xuân

Ý tưởng giải pháp của tôi là tạo ra phạm vi tùy chỉnh UsesX và triển khai BeanFactoryPostProcessor, điều này sẽ chuyển đổi mỗi BeanDefinition bằng UsesX thành bộ đơn cho mỗi XType. Ngoài ra, nó sẽ bổ sung thêm vòng loại cho hạt cà phê này, để làm cho nó có thể làm cho phương pháp nhà máy cho X và lựa chọn dựa trên tham số trong bộ điều khiển. Nhưng làm thế nào để thêm vòng loại này vào @Autowired trong các dịch vụ ngầm, mà không thay đổi các lớp học của họ?

UPD

Ok, Ví dụ, tôi muốn sử dụng db url "jdbc:mysql://Adb" khi A yêu cầu, và "jdbc:mysql://Bdb" khi B:

enum DatabaseType {A, B} 

@Controller 
@RequestMapping(/) 
class MyController { 
@Autowired ServiceProvider provider; // some way to get service by DatabaseType 
    void foo(@RequestParam DatabaseType dbType) { 
     ServiceA a = provider.getA(dbType); 
     a.bar(); 
     ServiceB b = provider.getB(dbType); 
     b.baz(); 
    } 
} 

@Service 
class ServiceA { 
    // Don't want to get information about different databases in services 
    @Autowired ServiceB b; 
    @Autowired ServiceC c; 
    @Autowired DaoFoo dao; 
    //... 
} 

@Service 
class ServiceB { 
    @Autowired ServiceC c; 
    @Autowired DaoFoo daoFoo; 
    @Autowired DaoBar daoBar; 
    //... 
} 

@Service 
class ServiceC { 
    @Autowired DaoBar daoBar; 
    //... 
} 

@Repository 
class DaoFoo { 
    DaoFoo(String dbURL) {/*...*/} 
} 

@Repository 
class DaoBar { 
    DaoFoo(String dbURL) {/*...*/} 
} 

Ngoài ra, nó là cần thiết để "jdbc:mysql://Adb""jdbc:mysql://Bdb" được cấu hình trong Cấu hình XML.

+0

Rất rõ ràng những gì đang được hỏi. Là ServiceA giả sử sử dụng Adb và ServiceB giả sử sử dụng Bdb ?? Thậm chí sau đó câu hỏi này vẫn làm cho ý nghĩa 0 – Snickers3192

Trả lời

1

Ví dụ của bạn hơi khó hiểu vì Service s được đặt tên là A và B, nhưng bạn cũng sử dụng A và B cho số DatabaseType của mình. Nhưng tôi nghĩ rằng tôi hiểu những gì bạn muốn.

Tôi không nghĩ rằng bạn có thể làm điều này với Autowired, nhưng bạn có thể làm cho Service s của mình là @Scope("prototype") và truy xuất chúng từ ngữ cảnh. Ngữ cảnh sẽ khởi tạo Service lần đầu tiên bạn yêu cầu, sau đó sử dụng lại cùng một bean khi cùng một đầu vào được cung cấp.

@Configuration 
public class ServiceProvider{ 
    ... 
    @Bean 
    @Scope("prototype") 
    public ServiceA serviceA(DatabaseType dbType) { 
     ... 
    } 

    @Bean 
    @Scope("prototype") 
    public ServiceB serviceB(DatabaseType dbType) { 
     ... 
    } 
} 

@Controller 
@RequestMapping(/) 
class MyController { 
    @Autowired 
    ConfigurableApplicationContext context 
    void foo(@RequestParam DatabaseType dbType) { 
     AutowireCapableBeanFactory beanFactory = context.getBeanFactory(); 
     ServiceA serviceA = (ServiceA)context.getBean("serviceA", dbType); 
     ... 
    } 
} 
1

Tạo một giao diện dịch vụ như:

interface ServiceInterface{ 
    public boolean isTheOne(String type); // or some suitable name. 
} 

tất cả các dịch vụ của bạn thì cần phải thực hiện giao diện này, sau đó trong bộ điều khiển

@Controller 
    @RequestMapping(/) 
    class MyController { 
    @Autowired 
    Set<ServiceInterface> provider; 

    void foo(@RequestParam DatabaseType dbType) { 
    ServiceInterface service = provider.stream().filter(s -> s.isTheOne(String dbType)); 
    service.bar(); 
    } 
    } 
3

Tôi muốn quấn lên yêu cầu của bạn để nó sẽ rõ ràng nếu tôi giúp bạn đúng.

  1. Bạn có một bộ @Service mà bạn không muốn sửa đổi.
  2. Tại thời điểm này, bạn chỉ có một triển khai loại X được sử dụng bởi các dịch vụ này.
  3. Lựa chọn thực hiện X được sử dụng trong các dịch vụ sẽ được xác định bởi XType enum, do đó sẽ có sẵn theo yêu cầu.
  4. Bạn muốn X loại hạt được cấu hình từ xml.

OP: Điều gì cần thực hiện X trong trường hợp một dịch vụ này được gọi là w/o XType?

Vì vậy, nếu hiểu biết của tôi là chính xác, có vẻ như bạn cần Proxy cho loại X. Trong phạm vi số Proxy này, bạn cần nhận được số này XType hoàn toàn (f.ex. đến ThreadLocal var). Khi sử dụng @Autowired, đậu được xác định theo loại ở vị trí đầu tiên. Do đó, bạn cần sử dụng triển khai thực hiện X hiện có cho proxing và trích xuất triển khai hiện tại của bạn và thực hiện mới thành loại khác.

Kết quả là bạn có thể kết thúc với sau:

interface newX { 
    void save(); 
} 

@Repository 
class DaoFoo implements newX { 
    public void save() {...}; 
} 

@Repository 
class DaoBar implements newX { 
    public void save() {...}; 
} 

class XImpl implements X, newX { 
    public final ThreadLocal<XType> currentXType = new ThreadLo...; 
    Map<XType, newX> mapping = .... 
    public void save() {mapping.get(currentXType.get()).save();}; 
} 
0

Bạn có thể duy trì XType của bạn như một Enumerator trong một tùy chỉnh Qualifier bằng cách phát triển @Interface. Hãy tìm thấy bên dưới một mẫu mà đề cập đến hệ thống dây điện có điều kiện của đậu dựa trên các loại khác nhau của kiểu dữ liệu:

@Target({ElementType.FIELD, 
     ElementType.METHOD, 
     ElementType.TYPE}) 
@Retention(RetentionPolicy.RUNTIME) 
@Qualifier 
public static @interface DBHost{ 

public static enum DatabaseType {  
A, 
B 
} 
} 


@Autowired 
@DBHost(DBHost.DatabaseType.A) 
ServiceBean serviceInstanceA; 

Tìm việc sử dụng thêm các chú thích Qualifier here

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