Springboot에서 Quartz 및 RabbitMQ를 통합하면 자동으로 실행되지 않도록 설정

7679 단어 framework
SpringBoot 2를 사용하여 Quartz와 RabbitMQ를 통합하는 것은 매우 간단하고 편리한 일이다. 심지어 제로 설정으로 운행할 수 있어 우리의 사용을 크게 편리하게 할 수 있다.그러나 지나치게 지능화된 것도 하나의 문제를 가져왔다. 바로 제어할 때 제어가 잘 되지 않는다는 것이다.예를 들어 내 프로젝트에Quartz가 통합되어 있지만 서로 다른 서버에 배치해야 한다. 그 중 한 서버는Quartz를 실행해야 하고 다른 서버는Quartz를 실행하지 말아야 한다.아시다시피 Quartz와 RabbitMQ 같은 프레임워크는 SpringBoot에 통합된 후에 모두 자동으로 실행되지만 다른 설정을 다른 서버에 포장할 수는 없습니다.
코드를 보면 이러한 자동 실행 프레임워크는 스프링의 SmartLifecycle 인터페이스를 실현하는 것을 발견했습니다. 자세히 보면:Spring SmartLifecycle은 용기의 모든 bean에서 불러오고 초기화되어 실행됩니다.
   /**
     *  start 。
* true start , false 。 */ public boolean isAutoStartup() { // false return true; }

이 방법이 관건이다.설명에 따르면 이 방법은false를 되돌릴 때 start () 방법을 자동으로 실행하지 않습니다.
1. Quartz를 먼저 봅니다.Quartz하면 핵심 클래스부터 볼 수 있다.우리는 작업의 시작과 정지가 모두 Quartz Scheduler와 관련이 있다는 것을 알고 있기 때문에 Quartz Scheduler의 start () 방법부터 살펴보자.debug를 통해 Scheduler Factory Bean을 위로 계속 찾습니다.
	//---------------------------------------------------------------------
	// Implementation of SmartLifecycle interface
	//---------------------------------------------------------------------

	@Override
	public void start() throws SchedulingException {
		if (this.scheduler != null) {
			try {
				startScheduler(this.scheduler, this.startupDelay);
			}
			catch (SchedulerException ex) {
				throw new SchedulingException("Could not start Quartz Scheduler", ex);
			}
		}
	}

SmartLifecycle 인터페이스를 구현한 것으로 보입니다.그러면 간단합니다. isAutoStartup 방법을 직접 찾아보세요. autoStartup 필드로 되돌아온 것을 보았습니다.
	@Override
	public boolean isAutoStartup() {
		return this.autoStartup;
	}

마침 봤어요.
	public void setAutoStartup(boolean autoStartup) {
		this.autoStartup = autoStartup;
	}

대성공은 Scheduler Factory Bean을 찾아서 set Auto Startup 방법을 사용하면 된다.
다음은 springboot2 통합quartz의 SchedulerFactoryBean 구성 코드입니다.
/**
 * @Description  SchedulerFactoryBean 。
 * @Author yangpeng
 * @Date 2018/9/18
 **/
@Component
public class SchedulerConfig implements SchedulerFactoryBeanCustomizer {

    @Value("${mongcent.init.task}")
    private boolean runTask = false;

    @Override
    public void customize(SchedulerFactoryBean schedulerFactoryBean) {
        // quartz , 
        if (!runTask) {
            schedulerFactoryBean.setAutoStartup(false);
        }
        schedulerFactoryBean.setStartupDelay(10);
        schedulerFactoryBean.setOverwriteExistingJobs(true);
    }
}

2. RabbitMQ를 봅니다.먼저 RabbitMQ의 시작 방법을 찾아서 자료를 찾아보면 RabbitListener Endpoint Registry임을 알 수 있습니다.start() 메서드는 MQ, RabbitListenerEndpointRegistry를 시작합니다.stop() 메서드는 MQ를 닫습니다.
	@Override
	public void start() {
		for (MessageListenerContainer listenerContainer : getListenerContainers()) {
			startIfNecessary(listenerContainer);
		}
	}

	/**
	 * Start the specified {@link MessageListenerContainer} if it should be started
	 * on startup or when start is called explicitly after startup.
	 * @param listenerContainer the container.
	 * @see MessageListenerContainer#isAutoStartup()
	 */
	private void startIfNecessary(MessageListenerContainer listenerContainer) {
		if (this.contextRefreshed || listenerContainer.isAutoStartup()) {
			listenerContainer.start();
		}
	}

보시다시피 MessageListenerContainer 클래스의 isAutoStartup 방법으로 MQ,listenerContainer를 실행할지 여부를 결정합니다.isAutoStartup () 의 값은 어디에서 나오는 것입니까?MessageListenerContainer의 초기화를 살펴보겠습니다. start () 방법에서 getListenerContainers () 방법에서 보십시오.
	/**
	 * @return the managed {@link MessageListenerContainer} instance(s).
	 */
	public Collection getListenerContainers() {
		return Collections.unmodifiableCollection(this.listenerContainers.values());
	}

이것을 다시 찾습니다.listener Containers는 어디서 왔나요?
	/**
	 * Create a message listener container for the given {@link RabbitListenerEndpoint}.
	 * 

This create the necessary infrastructure to honor that endpoint * with regards to its configuration. *

The {@code startImmediately} flag determines if the container should be * started immediately. * @param endpoint the endpoint to add. * @param factory the {@link RabbitListenerContainerFactory} to use. * @param startImmediately start the container immediately if necessary * @see #getListenerContainers() * @see #getListenerContainer(String) */ @SuppressWarnings("unchecked") public void registerListenerContainer(RabbitListenerEndpoint endpoint, RabbitListenerContainerFactory> factory, boolean startImmediately) { Assert.notNull(endpoint, "Endpoint must not be null"); Assert.notNull(factory, "Factory must not be null"); String id = endpoint.getId(); Assert.hasText(id, "Endpoint id must not be empty"); synchronized (this.listenerContainers) { Assert.state(!this.listenerContainers.containsKey(id), "Another endpoint is already registered with id '" + id + "'"); MessageListenerContainer container = createListenerContainer(endpoint, factory); this.listenerContainers.put(id, container); if (StringUtils.hasText(endpoint.getGroup()) && this.applicationContext != null) { List containerGroup; if (this.applicationContext.containsBean(endpoint.getGroup())) { containerGroup = this.applicationContext.getBean(endpoint.getGroup(), List.class); } else { containerGroup = new ArrayList(); this.applicationContext.getBeanFactory().registerSingleton(endpoint.getGroup(), containerGroup); } containerGroup.add(container); } if (startImmediately) { startIfNecessary(container); } } }


아래 두 줄 코드 보셨어요?
MessageListenerContainer container = createListenerContainer(endpoint, factory);
this.listenerContainers.put(id, container);

createListenerContainer 방법에서 본 것은 RabbitListenerContainerFactory입니다.createListenerContainer 방법으로 생성되었습니다.
MessageListenerContainer listenerContainer = factory.createListenerContainer(endpoint);

실현 클래스를 보십시오. Abstract Rabbit Listener Container Factory에서 많은 속성이 설정된 것을 보았습니다. 그 중에서 우리가 관심을 가지는 auto Startup이 있습니다. 되돌아오는 것은this입니다.autoStartup
		else if (this.autoStartup != null) {
			instance.setAutoStartup(this.autoStartup);
		}

자연스럽게 set 방법을 찾았어요.
	/**
	 * @param autoStartup true for auto startup.
	 * @see AbstractMessageListenerContainer#setAutoStartup(boolean)
	 */
	public void setAutoStartup(Boolean autoStartup) {
		this.autoStartup = autoStartup;
	}

그렇다면 어떻게 해야만 Abstract Rabbit Listener Container Factory의 setAutoStartup 방법을 호출할 수 있습니까?이 유형의 이름이 좀 낯익다고 생각하십니까? 이것은 추상적인 유형입니다. 우리는 어떤 유형이 있는지 보러 갑시다.보시면 Simple Rabbit Listener Container Factory를 보실 수 있습니다. 이것이 바로 저희가 소비자 속성을 설정한 그 설정 클래스 아닙니까, 완벽합니다!setAutoStartup 메서드를 직접 호출하면 해결됩니다.
마지막으로 설정을 제공합니다.
    @Bean(name = "myRabbitListenerContainer")
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        // 
        if (!runMq) {
            // 
            factory.setAutoStartup(false);
        }
        return factory;
    }

 
결어: 한 바퀴 크게 돌았지만 설정에 두 줄의 코드를 넣었을 뿐, 아무 소용이 없는 것 같다.그러나 이 한 바퀴를 보면 저는 스프링의 시작 과정에 대해 더 많은 인식을 가지게 되었고 우수한 프레임워크의 디자인 사고방식을 배웠습니다. 이것은 매우 할 만한 일입니다.

좋은 웹페이지 즐겨찾기