io.hekate.spring.boot.HekateConfigurer Maven / Gradle / Ivy
Show all versions of hekate-all Show documentation
/*
* Copyright 2020 The Hekate Project
*
* The Hekate Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.hekate.spring.boot;
import io.hekate.codec.CodecFactory;
import io.hekate.codec.CodecService;
import io.hekate.core.Hekate;
import io.hekate.core.Hekate.LifecycleListener;
import io.hekate.core.HekateBootstrap;
import io.hekate.core.HekateFutureException;
import io.hekate.core.PropertyProvider;
import io.hekate.core.plugin.Plugin;
import io.hekate.core.service.ServiceFactory;
import io.hekate.spring.bean.HekateSpringBootstrap;
import io.hekate.spring.bean.codec.CodecServiceBean;
import io.hekate.spring.boot.cluster.HekateClusterServiceConfigurer;
import io.hekate.spring.boot.coordination.HekateCoordinationServiceConfigurer;
import io.hekate.spring.boot.election.HekateElectionServiceConfigurer;
import io.hekate.spring.boot.lock.HekateLockServiceConfigurer;
import io.hekate.spring.boot.messaging.HekateMessagingServiceConfigurer;
import io.hekate.spring.boot.network.HekateNetworkServiceConfigurer;
import io.micrometer.core.instrument.MeterRegistry;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* « start hereAuto-configuration for {@link Hekate} instances.
*
* Overview
*
* This class provides support for automatic configuration and bootstrapping of {@link Hekate} instances via Spring Boot. In order to enable this auto-configuration the
* 'hekate-spring-boot' dependency must be added to a Spring Boot-enabled project (see 'Module dependency' section below) and {@link
* EnableHekate @EnableHekate} annotation must be placed on application class (see Usage example section
* below).
*
*
* Module Dependency
*
* Spring Boot integration is provided by the 'hekate-spring-boot' module and can be imported into the project dependency management system
* as in the example below:
*
*
*
*
* {@code
*
* io.hekate
* hekate-spring-boot
* REPLACE_VERSION
*
* }
*
*
* {@code
* compile group: 'io.hekate', name: 'hekate-spring-boot', version: 'REPLACE_VERSION'
* }
*
*
* {@code
*
* }
*
*
*
*
* Usage Example
*
* The code example below shows how {@link Hekate} auto-configuration can be used in a Spring Boot-enabled applications.
*
*
*
* First lets define some component that depends on {@link Hekate} instance.
* ${source: MyComponent.java#example}
* ...and a Spring Boot application (note the {@link EnableHekate @EnableHekate} annotation)...
* ${source: MyApplication.java#example}
* Note that {@link Hekate} instance doesn't require any manual construction.
*
*
* Registering and Configuring Services
*
* This class automatically registers all application-provided {@link Bean Bean}s of {@link ServiceFactory} type into the auto-configured
* {@link Hekate} instance.
*
*
*
* Additionally each service has its own auto-configuration class that simplifies configuration and registration of services and
* components.
* Please see the documentation of the following classes:
*
*
* - {@link HekateClusterServiceConfigurer}
* - {@link HekateMessagingServiceConfigurer}
* - {@link HekateNetworkServiceConfigurer}
* - {@link HekateLockServiceConfigurer}
* - {@link HekateCoordinationServiceConfigurer}
* - {@link HekateElectionServiceConfigurer}
*
*
* Configuration Options
*
* The following application properties can be used to configure the constructed {@link Hekate} instance:
*
*
* - {@link HekateBootstrap#setNodeName(String) 'hekate.node-name'}
* - {@link HekateBootstrap#setClusterName(String) 'hekate.cluster-name'}
* - {@link HekateBootstrap#setRoles(List) 'hekate.roles'}
* - {@link HekateBootstrap#setProperties(Map) 'hekate.properties'}
* - {@link HekateBootstrap#setConfigReport(boolean)} 'hekate.config-report'}
*
*
* Deferred Cluster Joining
*
* It is possible to control the timing of when {@link Hekate} node will start joining the cluster by specifying the following properties:
*
*
* - {@link HekateSpringBootstrap#setDeferredJoin(boolean) 'hekate.deferred-join'} - if set to {@code false} (default value) then joining
* will happen synchronously during the Spring Application context initialization
* - {@link HekateSpringBootstrap#setDeferredJoin(boolean) 'hekate.deferred-join'} - if set to {@code true} then joining will be deferred
* until the Spring Application context gets fully initialized (signalled by {@link ApplicationReadyEvent}).
*
*
*
* Furthermore it is also possible to completely disable joining to the cluster by setting the {@code 'hekate.deferred-join-condition'}
* property value to {@code 'manual'}. In such case it is up to the application logic to decide on when to call the {@link Hekate#join()}
* method in order to start joining the cluster. Alternative value of this property is {@code 'app-ready'} which will fall back to the
* default behavior.
*
*/
@Configuration
@ConditionalOnMissingBean(Hekate.class)
@ConditionalOnProperty(name = "hekate.enable", havingValue = "true", matchIfMissing = true)
public class HekateConfigurer {
/**
* Handler for {@link HekateSpringBootstrap#setDeferredJoin(boolean) deferred join}.
*
*
* Performs {@link Hekate#join()} when {@link ApplicationReadyEvent} gets fired.
*
*/
@Component
@ConditionalOnProperty(value = "hekate.deferred-join-condition", havingValue = "app-ready", matchIfMissing = true)
static class HekateDeferredJoinReadyHandler implements ApplicationListener {
private final Hekate hekate;
/**
* Constructs a new instance.
*
* @param hekate Node.
*/
public HekateDeferredJoinReadyHandler(Hekate hekate) {
this.hekate = hekate;
}
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
try {
// Handle deferred join when application is ready.
if (hekate.state() == Hekate.State.INITIALIZED) {
hekate.join();
}
} catch (InterruptedException e) {
throw new ApplicationContextException("Thread got interrupted while awaiting for cluster join.", e);
} catch (HekateFutureException e) {
throw new ApplicationContextException("Failed to join the cluster.", e);
}
}
}
private final CodecFactory