Сочетание весны, кварца и Hazelcast - PullRequest
8 голосов
/ 28 декабря 2011

Я пытаюсь разработать разумно масштабируемую инфраструктуру пакетной обработки для веб-приложения, которое я пишу.

Я использую Spring MVC для веб-приложения со специальным слоем DAO (для доступа к базе данных требуется экземпляр UnitOfWork , созданный из UnitOfWorkFactory , который установлен как @ Автоматически подключается и вводится во время выполнения Spring).

Я использую аннотации Spring Scheduler (@Scheduled) для планирования задач, однако я хочу, чтобы эти задачи выполнялись на разных машинах в моем кластере. Каждое пакетное задание должно быть подобрано на одной из машин кластера и затем выполнено.

Hazelcast казался естественным подходом для этого, поскольку дизайн Distributed Execution казался действительно простым и элегантным для этой цели.

Я столкнулся с проблемой, которая, похоже, не описана в документации. Я прочитал документацию о Spring Integration , но, похоже, основное внимание уделяется настройке Hazelcast с использованием Spring (что я уже сделал).

Когда планировщик указывает, что задача запускается, я хочу создать новый экземпляр задачи ( Callable экземпляр) и передать его DistributedExecutor . Когда машина кластера получает задачу для запуска, мне нужен контейнер Spring на машине кластера, чтобы внедрить экземпляр UnitOfWorkFactory в пакетную задачу, прежде чем задача попытается выполнить ее. Каждый из кластеров начинается с Spring и будет иметь экземпляр UnitOfWorkFactory , уже созданный с правильными деталями, проблема заключается в получении экземпляра UnitOfWorkFactory , внедренного в мою задачу.

Кто-нибудь знает, как я могу настроить свое приложение так, чтобы Hazelcast мог автоматически UnitOfWorkFactory вводиться при запуске Callable ? Я попытался пометить Callable как Сериализуемый и ApplicationContextAware , но я все еще получаю NullPointerException при попытке запустить задачу.

Я мог бы получить доступ к ApplicationContext напрямую, однако я бы предпочел не делать этого, поскольку он ограничит тестируемость моих задач и введет жесткую зависимость от Spring для моих пакетных заданий.

1 Ответ

7 голосов
/ 28 декабря 2011

В версии 2.1 Hazelcast может внедрять контекст Spring и / или компоненты Spring в управляемые объекты Hazelcast.

Если вы конфигурируете Hazelcast с использованием конфигурации Hazelcast Spring и комментируете bean-компонент с использованием @SpringAware, Hazelcast попросит Spring ввести зависимости этого bean-компонента.

<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 или любой bean-компонент Spring в управляемый объект Hazelcast для версий, предшествующих 2.1.

В группе Hazelcast есть сообщение с вопросом об этой функции.

Инъекция Hazelcast / Dependency для 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");
        ....
    }
}
...