2016-08-22 10 views
6

私はいくつかの独立したBean Xを持つプロジェクトを持っています。これは一連のサービスにautowiredされています。サービスは相互に使用され、最終的にはシングルエントリーポイント(コントローラ)で使用されます。今や新しい要件があります:Xのいくつかのバージョンを実装し、エントリポイントのパラメータ(enum XType)に従って使用することを決定します。サービスを変更することなくそれを行うことはいいですね。Springでの暗黙的なautowiring

解決策私の考えは、カスタムスコープUsesXを作成してBeanFactoryPostProcessorを実装して、UsesXで各BeanDefinitionを各XTypeのシングルトンのセットに変換することです。また、このBeanに修飾子を追加することで、Xのファクトリメソッドとコントローラのパラメータベースの選択を行うことができます。しかし、この修飾子をクラスを変更せずに暗黙的にサービス内の@Autowiredに追加する方法はありますか?

UPD

[OK]を、例では、私はAが要求されたとき、DBのURL "jdbc:mysql://Adb"を使用したい、と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を使用すると仮定していますか?それでもなおこの質問は0感覚 – Snickers3192

答えて

1

あなたのServiceの名前はAとBですが、DatabaseTypeの場合はAとBも使用しているため、少し混乱します。しかし、私はあなたが欲しいものを理解していると思います。

私はAutowiredでこれを行うことはできませんが、Service@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

のようなサービス・インターフェースを作成します。そして、コントローラ

@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

で、私はそれようにあなたの要件をラップしたい、このインタフェースを実装する必要が

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

すべてのサービスを私はあなたが正しいことを明らかにするでしょう。

  1. あなたは変更したくないセットが@Serviceです。
  2. この時点では、このサービスで使用されているXタイプの実装は1つだけです。
  3. サービスで使用されるX実装の選択は、XType enumによって定義されます。これは、要求から利用可能になります。
  4. XタイプのBeanをxmlから設定する必要があります。

OP:このサービスの1つが「XType」と呼ばれる場合には、X実装を使用する必要がありますか?

私の理解が正しい場合はXタイプのためにProxyが必要なようです。 このProxyの範囲内で暗黙のうちにXType(f.ex.からThreadLocalまで)を取得する必要があります。 @Autowiredが使用されているため、豆は最初にタイプ別に識別されます。したがって、既存の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

関連する問題