2016-09-15 3 views
1

현재 새로운 방법과 아키텍처를 배우기 위해 스프링 독립형 프로그램을 만들고 있습니다.
지난 며칠 동안 나는 스케줄러를 배우려고 노력했다. 전에는 사용하지 않았기 때문에 가능한 여러 가지 방법을 다루는 기사를 읽었습니다. 그 중 두 가지가 특히 흥미 롭습니다 : 봄 nativ @Scheduler와 Quartz.자바 스케줄러 스프링 대 석영

내가 읽은 것부터 봄은 Quartz보다 훨씬 작으며 훨씬 기본입니다. 그리고 석영은 스프링과 함께 사용하기 쉽지 않습니다 (자동 배선 및 부품 때문에).

내 문제는 지금 내가 이해할 수없는 한 가지가 있다는 것입니다.
비동기 적으로 작업을 실행하기 위해 두 가지 방법 모두 병렬 스레드를 만들고 있습니다. 하지만 이제 메인 애플리케이션에 spring @Service가 있으면, 정보가있는 HashMap을 보유하고있을 것입니다. 데이터는 사용자 상호 작용으로 업데이트되고 변경됩니다. 병렬 거기에 스케줄러가 있습니다. 그리고 스케줄러는 이제 메인 어플리케이션에서도이 HashMap을 사용하고 싶어합니다. 이것은 가능한가?
아니면 잘못된 것이 있습니까? @Async 주석도 있기 때문에 차이점을 이해하지 못했습니다. 스케줄러 자체는 이미 메인 코퍼스와 병렬이기 때문에 그렇지 않습니까?

이 (합산, 두 가지 질문 :

  • 이, 5 초마다 실행되는 스케줄러로 구현하는 작업이 메인 프로그램 내에서 서비스의 밖으로의 HashMap을 사용할 수 있습니다 (봄 @Scheduler과/또는 석영에?)
  • 은 왜 @Async 주석이 있습니다. 아닙니다 스케줄러가 이미 주요 공정에 평행?

를)

답변

3

을 나는 철을해야 어떤 버전의 Spring을 사용하고 있는지에 대한 가정을 배우고 있지만, 스프링 부트 또는 상당히 새로운 버전을 사용하고 있다고 가정 할 것입니다. 따라서 주석이 Spring의 버전. 이것은 귀하의 두 가지 질문에 최선을 다해 답변 할 수 있습니다 :

5 초마다 실행되고, 스케줄러로 구현되는 작업은 메인 프로그램 내부의 서비스에서 HashMap을 사용할 수 있습니까? (봄에 @Scheduler 및/또는 Quartz?)

예, 절대적으로! 가장 쉬운 방법은 해당 해시 맵이 정적으로 선언되어 있는지 확인하는 것입니다. 예약 된 작업에서 해시 맵에 액세스하려면 서비스 클래스를 자동 작성하거나 해시 맵에 대한 정적 get 함수를 작성하십시오.

다음은 구독자 집합에 예약 된 메시지를 보내야하는 최근의 Vaadin 프로젝트의 예입니다.

SchedulerConfig.class

@Configuration 
@EnableAsync 
@EnableScheduling 
public class SchedulerConfig { 

    @Scheduled(fixedDelay=5000) 
    public void refreshVaadinUIs() { 
     Broadcaster.broadcast( 
       new BroadcastMessage(
        BroadcastMessageType.AUTO_REFRESH_LIST 
       ) 
     ); 
    } 

} 

Broadcaster.class

public class Broadcaster implements Serializable { 

    private static final long serialVersionUID = 3540459607283346649L; 

    private static ExecutorService executorService = Executors.newSingleThreadExecutor(); 

    private static LinkedList<BroadcastListener> listeners = new LinkedList<BroadcastListener>(); 

    public interface BroadcastListener { 
     void receiveBroadcast(BroadcastMessage message); 
    } 

    public static synchronized void register(BroadcastListener listener) { 
     listeners.add(listener); 
    } 

    public static synchronized void unregister(BroadcastListener listener) { 
     listeners.remove(listener); 
    } 

    public static synchronized void broadcast(final BroadcastMessage message) { 
     for (final BroadcastListener listener: listeners) 
      executorService.execute(new Runnable() { 
       @Override 
       public void run() { 
        listener.receiveBroadcast(message); 
       } 
      }); 
    } 
} 

왜 @Async 주석이 있습니다. 스케줄러가 이미 주 프로세스와 병렬되지 않았습니까?

예, 스케줄러는 자체 스레드에서 실행되지만 장기 실행 태스크 (예 : 완료하는 데 오랜 시간이 걸리는 원격 서버에 대한 SOAP 호출 수행)에서 스케줄러에게는 어떤 현상이 발생합니까?

@Async 주석은 스케줄링에 필요하지 않지만 스케줄러에 의해 장기 실행 기능이 호출되는 경우 매우 중요합니다.

이 주석은 특정 작업을 수행하고 Spring의 TaskExecutor에게 현재 스레드 대신 자체 스레드에서 실행하도록 요청하는 데 사용됩니다. @Async 주석은 함수를 즉시 반환하지만 나중에 TaskExecutor에 의해 실행됩니다.

@EnableAsync 또는 @Async 주석이 없으면 호출 한 함수는 TaskScheduler가 동일한 스레드에서 실행될 때이를 보류합니다. 장시간 실행하는 경우 스케줄러가 중지되고 리턴 될 때까지 다른 스케줄 된 기능을 실행할 수 없습니다.

나는 Spring's Documentation about Task Execution and Scheduling을 읽을 것을 제안합니다. Spring의 TaskScheduler 및 TaskExecutor에 대한 훌륭한 설명을 제공합니다.