8

私が書いている webapp 用の適度にスケーラブルなバッチ処理フレームワークを開発する方法を考え出そうとしています。

カスタムDAOレイヤーを備えたWebアプリケーションにSpring MVCを使用しています(データベースにアクセスするには、 @Autowired として設定され、Springによって実行時に注入されるUnitOfWorkFactoryからUnitOfWorkインスタンスを構築する必要があります)。

Spring Scheduler アノテーション (@Scheduled) を使用してタスクをスケジュールしていますが、これらのタスクをクラスター内の別のマシンで実行したいと考えています。各バッチ ジョブは、クラスター マシンの 1 つによって取得され、実行される必要があります。

分散実行の設計はこの目的のために非常にシンプルでエレガントに見えたので、 Hazelcastはこれに自然に適合するように思われました。

ドキュメントでカバーされていないように見える問題が発生しています。Spring Integrationに関するドキュメントを読みましたが、これは Spring を使用して Hazelcast を構成する方法に焦点を当てているようです (これは既に行っています)。

スケジューラがタスクの開始を示したら、タスクの新しいインスタンス ( Callableインスタンス) を作成し、それをDistributedExecutorに送信します。クラスター マシンが実行するタスクを受け取ると、タスクが実行を試みる前に、クラスター マシン上の Spring コンテナーがUnitOfWorkFactoryインスタンスをバッチ タスクに挿入する必要があります。各クラスターは Spring で始まり、UnitOfWorkFactoryが正しい詳細で既にインスタンス化されています。問題は、UnitOfWorkFactoryインスタンスをタスクに挿入することです。

Callableが開始されたときに Hazelcast がUnitOfWorkFactoryを自動的に注入できるように、アプリケーションを構成する方法を知っている人はいますか? Callableを Serializable およびApplicationContextAwareとしてマークしようとしましたが、タスクを実行しようとするとNullPointerExceptionが発生します。

ApplicationContext に直接アクセスすることもできますが、タスクのテスト容易性が制限され、バッチ ジョブが Spring に強く依存するようになるため、アクセスしたくありません。

4

1 に答える 1

7

バージョン 2.1 までに、Hazelcast は Spring コンテキストおよび/または Spring Bean を Hazelcast 管理対象オブジェクトに注入できます。

Hazelcast Spring 構成を使用して Hazelcast を構成し、 を使用して Bean に注釈を付けると@SpringAware、Hazelcast はその Bean の依存関係を注入するよう Spring に要求します。

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:hz="http://www.hazelcast.com/schema/spring"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.hazelcast.com/schema/spring
            http://www.hazelcast.com/schema/spring/hazelcast-spring-2.1.xsd">
   <hz:hazelcast id="instance">
      <hz:config>
         <hz:group name="dev" password="password"/>
         <hz:network port="5701" port-auto-increment="false">
            <hz:join>
                <hz:multicast enabled="false" />
                <hz:tcp-ip enabled="true">
                    <hz:members>10.10.1.2, 10.10.1.3</hz:members>
                </hz:tcp-ip>
            </hz:join>
         </hz:network>
         ...
      </hz:config>
   </hz:hazelcast>

   <bean id="someBean" class="com.hazelcast.examples.spring.SomeBean" 
          scope="singleton" />
   ...
</beans>

@SpringAware 
public class SomeTask implements Callable<Long>, ApplicationContextAware, Serializable {
   private transient ApplicationContext context;
   private transient SomeBean someBean;

   public Long call() throws Exception {
     return someBean.value;
   }

   public void setApplicationContext(final ApplicationContext applicationContext)
       throws BeansException {
      context = applicationContext;
   }

   @Autowired
   public void setSomeBean(final SomeBean someBean) {
      this.someBean = someBean;
   }
}

2.1 より古いバージョンの場合:

Hazelcast の 2.1 より前のバージョンは Spring に対応していないため、Spring コンテキストまたは任意の Spring Bean を 2.1 より前のバージョンの Hazelcast 管理対象オブジェクトに注入することはできません。

Hazelcast グループにこの機能について質問する投稿があります。

Hazelcast / Callable の依存性注入

既にご存知かもしれませんが、Hazelcast グループで提案されているように、次を使用して Spring ApplicationContext にアクセスできます。

public class ApplicationContextProvider implements ApplicationContextAware {
    private static ApplicationContext context = null;

    public synchronized void setApplicationContext(ApplicationContext applicationContext)
        throws BeansException {
        if(context == null) {
            context = applicationContext;
        }
    }

    public static <T> T getBean(String name) {
        return (T) context.getBean(name);
    }
}  

class MyCallable implements Callable {
    ....
    public Object call() throws Exception {
        SomeServiceBean bean = ApplicationContextProvider.getBean("serviceBean");
        ....
    }
}
于 2011-12-28T10:05:22.227 に答える