10

複雑な初期化スキームを持つ一連のクラスがあります。基本的に、取得する必要のあるインターフェイスから始めて、一連の呼び出しを行い、最終的にそのインターフェイスを実装するオブジェクトを作成します。

これを処理するために、インターフェイスを指定して最終的なオブジェクトを生成できるファクトリ クラスを作成しました。このファクトリを Bean にし、さまざまなサービス Bean を、実装するインターフェイスのパラメータを使用して、このファクトリ オブジェクトを介してインスタンス化されるように XML で指定しました。

これはうまく機能し、必要な豆を完全に手に入れることができます。残念ながら、コンポーネントのスキャンによって発見されたコントローラー クラスからそれらにアクセスしたいと考えています。ここで @Autowired を使用していますが、Spring はこれらがどのタイプのオブジェクトであるかを認識していないようです。@Autowired はタイプによって機能するため、私は SOL です。

ここで @Resource(name="beanName") を使用すると完全に機能しますが、一部の Bean に @Resource を使用し、他の Bean に @Autowired を使用するのは奇妙に思えます。

タイプごとに異なるファクトリーメソッドを持たずに、これらの Bean ごとにファクトリーが作成するインターフェースを Spring に知らせる方法はありますか?

ちなみに、私はSpring 2.5.6を使用しています。それ以外の場合は、JavaConfig全体を忘れてしまいます。

工場クラス:

<T extends Client> T buildService(Class<T> clientClass) {
  //Do lots of stuff with client class and return an object of clientClass.
}

アプリのコンテキスト:

<bean id="serviceFactoryBean" class="com.captainAwesomePants.FancyFactory" />
<bean id="userService" factory-bean="serviceFactoryBean" factory-method="buildService">
   <constructor-arg value="com.captain.services.UserServiceInterface" />
</bean>
<bean id="scoreService" factory-bean="serviceFactoryBean" factory-method="buildService">
   <constructor-arg value="com.captain.services.ScoreServiceInterface" />
</bean>  

私のコントローラー:

public class HomepageController {

   //This doesn't work
   @Autowired @Qualifier("userService") UserServiceInterface userService;

   //This does
   @Resource(name="scoreService") ScoreServiceInterface scoreService;
}
4

3 に答える 3

8

ファクトリ パターンをさらに一歩進めて、ファクトリを SpringFactoryBeanクラスとして実装することをお勧めします。FactoryBeanインターフェイスには、getObjectType()ファクトリが返す型を検出するために呼び出すメソッドがあります。これにより、ファクトリが適切な値を返す限り、オートワイヤリングに慣れることができます。

于 2011-01-31T08:18:26.660 に答える
5

私も同様の問題を抱えていましたが、JMockit (使用する必要があるテスト フレームワーク) を使用して、自動配線された依存関係のモックアウトされた実装を作成するために単一のファクトリを使用したかったのです。

インターウェブで満足のいく解決策が見つからなかったので、私にとって非常にうまく機能する簡単な解決策をまとめました。

私のソリューションでもSpringFactoryBeanを使用していますが、すべてのBeanを作成するために単一のファクトリBeanのみを使用しています(元の質問者が望んでいたようです)。

FactoryBean私の解決策は、実際の単一のファクトリの周りにラッパー を提供するファクトリ オブ ファクトリのメタファクトリを実装することでした。

JMockit モック Bean ファクトリの Java は次のとおりです。

public class MockBeanFactory<C> implements FactoryBean<C> {

    private Class<C> mockBeanType;
    protected MockBeanFactory(){}

    protected  <C> C create(Class<C> mockClass) {
        return Mockit.newEmptyProxy(mockClass);
    }

    @Override
    public C getObject() throws Exception {
        return create(mockBeanType);
    }

    @Override
    public Class<C> getObjectType() {
        return mockBeanType;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public static class MetaFactory {
        public <C> MockBeanFactory<C> createFactory(Class<C> mockBeanType) {
            MockBeanFactory<C> factory = new MockBeanFactory<C>();
            factory.mockBeanType = mockBeanType;
            return factory;
        }
    }
}

次に、Spring コンテキストの XML ファイルで、特定の Bean タイプのファクトリを作成するメタ ファクトリを簡単に作成できます。

<bean id="metaFactory" class="com.stackoverflow.MockBeanFactory$MetaFactory"/>

<bean factory-bean="metaFactory" factory-method="createFactory">
    <constructor-arg name="mockBeanType" value="com.stackoverflow.YourService"/>
</bean>

元の質問者の状況でこれを機能させるには、FactoryBeansを のラッパー/アダプターにするように微調整できserviceFactoryBeanます。

public class FancyFactoryAdapter<C> implements FactoryBean<C> {

    private Class<C> clientClass;
    private FancyFactory serviceFactoryBean;

    protected FancyFactoryAdapter(){}

    @Override
    public C getObject() throws Exception {
        return serviceFactoryBean.buildService(clientClass);
    }

    @Override
    public Class<C> getObjectType() {
        return clientClass;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public static class MetaFactory {

        @Autowired FancyFactory serviceFactoryBean;

        public <C> FancyFactoryAdapter<C> createFactory(Class<C> clientClass) {
            FancyFactoryAdapter<C> factory = new FancyFactoryAdapter<C>();
            factory.clientClass = clientClass;
            factory.serviceFactoryBean = serviceFactoryBean;
            return factory;
        }
    }
}

次に、XML で ( userServiceFactoryid とBean id は、注釈userServiceを操作するためにのみ必要であることに注意してください):@Qualifier

<bean id="metaFactory" class="com.stackoverflow.FancyFactoryAdapter$MetaFactory"/>

<bean id="userServiceFactory" factory-bean="metaFactory" factory-method="createFactory">
    <constructor-arg name="clientClass" value="com.captain.services.UserServiceInterface"/>
</bean>

<bean id="userService" factory-bean="userServiceFactory"/>

<bean id="scoreServiceFactory" factory-bean="metaFactory" factory-method="createFactory">
    <constructor-arg name="clientClass" value="com.captain.services.ScoreServiceInterface"/>
</bean>

<bean id="scoreService" factory-bean="scoreServiceFactory"/>

たった 1 つの小さな Java クラスとボイラープレート構成のほんの一部、およびカスタム Bean ファクトリだけで、すべての Bean を作成し、Spring にそれらを正常に解決させることができます。

于 2012-09-09T22:34:40.990 に答える
3

以下を使用してこれを達成できるはずです。

<bean id="myCreatedObjectBean" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetClass">
        <value>com.mycompany.MyFactoryClass</value>
    </property>
    <property name="targetMethod">
        <value>myFactoryMethod</value>
    </property>
</bean>

次に、 @Resource または @Autowired + @Qualifier のいずれかを使用して、オブジェクトに直接注入できます。

于 2011-11-28T15:57:39.137 に答える