2016-08-22 39 views
6

我有一個獨立的bean X的項目,這是在一堆服務中自動裝配的。服務被相互使用,並最終用於單個入口點(控制器)。現在有了新的要求:實現X的多個版本,並根據入口點的參數(枚舉XType)決定使用哪一個版本。在不改變服務的情況下做到這一點很好。在春天隱式合格的自動裝配

我對解決方案的想法是創建自定義範圍UsesX並實現BeanFactoryPostProcessor,這將使用UsesX將每個BeanDefinition轉換爲每個XType的單例集。此外,它還會爲此Bean添加限定符,以便爲控制器中的X和基於參數的選擇創建工廠方法。但是,如何在隱含的情況下將此限定符添加到服務@Autowired中,而無需更改它們的類?

UPD

好,例如,我想用分貝URL "jdbc:mysql://Adb"A要求,而當B"jdbc:mysql://Bdb"

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) {/*...*/} 
} 

另外,還需要"jdbc:mysql://Adb""jdbc:mysql://Bdb"中配置XML配置。

+0

非常清楚問什麼更多的使用。 ServiceA假設使用Adb和ServiceB假設使用Bdb?即使這樣,這個問題仍然有意義 – Snickers3192

回答

1

您的示例有點令人困惑,因爲您的Service被命名爲A和B,但您也可以使用A和B作爲您的DatabaseType。但我想我明白你想要什麼。

我不認爲你可以用Autowired做到這一點,但你可以使Service s爲@Scope("prototype")並從上下文中檢索它們。上下文應在您第一次請求時實例化Service,然後在提供相同輸入時重用相同的bean。

@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

創建像一個服務接口:

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

所有的服務,那麼需要實現這個接口,然後在控制器

@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

我想包你的要求,使其如果我找到你的話,我會很清楚的。

  1. 你有一套你不想修改的@Service
  2. 在這一刻,你只有一個實現X這個服務使用的類型。
  3. 要在服務中使用的X實現的選擇將由XType enum定義,而enum又可以根據請求提供。
  4. 您想要X類型的豆可以從xml配置。

OP:什麼X應執行的情況下被使用,如果這個服務中的一個將被稱爲W/O XType

所以,如果我的理解是正確的,你似乎需要ProxyX類型。 在此Proxy內,您需要隱式獲取此XType(f.ex.至ThreadLocal var)。 當使用@Autowired時,bean首先按類型標識。因此,您需要使用已有的X實現進行代理,並將當前的實現和新的實現提取到不同的類型。

正如你可能與下列最終結果:

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

您可以通過開發@Interface定製Qualifier內保持你的xtype作爲一個枚舉。 請找出其中提到根據不同類型的數據類型的豆的條件接線樣本如下:

@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; 

查找預選賽註釋here