- 1. Main mode entrance
- 2. The third phase of Elasticsearch initialization
-
- 1. Construct restController when constructing node node object
- 2. Perform the operation of initializing RestHanders at the end of the node construction object.
- 3. Take the RestGetIndicesAction object registered in the handler as an example.
-
- 1. Inherited BaseRestHandler, the routes method is used as routing rules, and the parent class calls the prepareRequest implementation of the subclass.
- 2. BaseRestHandler implements the RestHandler interface
1. Main mode entrance
Path:
org.elasticsearch.bootstrap.Elasticsearch
/** * Start the main entry point for elasticsearch. */ public static void main(final String[] args) {<!-- --> Bootstrap bootstrap = initPhase1(); assert bootstrap != null; try {<!-- --> initPhase2(bootstrap); initPhase3(bootstrap); } catch (NodeValidationException e) {<!-- --> bootstrap.exitWithNodeValidationException(e); } catch (Throwable t) {<!-- --> bootstrap.exitWithUnknownException(t); } }
There are three initialization phases here. You can look directly at initPhase3
2. The third phase of Elasticsearch initialization
/** *The third phase of initialization *Phase 3 includes everything after initializing the security manager. Until now, the system has been single-threaded. This phase can spawn threads, write logs, and is subject to security manager policies. * At the end of phase 3, the system is ready to accept requests and the main thread is ready to terminate. this means: * The node component has been built and started * Cleanup completed (e.g. security settings turned off) * At least one thread other than the main thread is active and will remain active after the main thread terminates * The parent CLI process has been notified that the system is ready */ private static void initPhase3(Bootstrap bootstrap) throws IOException, NodeValidationException {<!-- --> //Call the checkLucene() function to check Lucene checkLucene(); //Create a Node object and override the validateNodeBeforeAcceptingRequests method for node verification before accepting requests. Node node = new Node(bootstrap.environment()) {<!-- --> @Override protected void validateNodeBeforeAcceptingRequests( final BootstrapContext context, final BoundTransportAddress boundTransportAddress, List<BootstrapCheck> checks ) throws NodeValidationException {<!-- --> BootstrapChecks.check(context, boundTransportAddress, checks); } }; //Use bootstrap.spawner() and the previously created node object to instantiate an Elasticsearch object and assign it to the INSTANCE variable. INSTANCE = new Elasticsearch(bootstrap.spawner(), node); //Turn off security settings IOUtils.close(bootstrap.secureSettings()); //Start the INSTANCE object, node will start and maintain a living thread INSTANCE.start(); //If the command line parameter specifies daemonize, remove the log configuration output by the console. if (bootstrap.args().daemonize()) {<!-- --> LogConfigurator.removeConsoleAppender(); } //Send a CLI flag to indicate that the server is ready to accept requests. bootstrap.sendCliMarker(BootstrapInfo.SERVER_READY_MARKER); //If the command line parameter specifies daemonize, close the stream; otherwise, start the CLI monitoring thread. if (bootstrap.args().daemonize()) {<!-- --> bootstrap.closeStreams(); } else {<!-- --> startCliMonitorThread(System.in); } }
Among them, INSTANCE.start();
is as follows, which means that the node is started and the surviving thread is running.
private void start() throws NodeValidationException {<!-- --> node.start(); keepAliveThread.start(); }
1. Construct restController when constructing the node node object
public Node(Environment environment) {<!-- --> this(environment, PluginsService.getPluginsServiceCtor(environment), true); } /** *Constructs a node * Initialization of nodes */ protectedNode( final Environment initialEnvironment, final Function<Settings, PluginsService> pluginServiceCtor, boolean forbidPrivateIndexSettings ) {<!-- --> //Omit code. . . . //restController will be initialized inside ActionModule actionModule = new ActionModule( settings, clusterModule.getIndexNameExpressionResolver(), settingsModule.getIndexScopedSettings(), settingsModule.getClusterSettings(), settingsModule.getSettingsFilter(), threadPool, pluginsService.filterPlugins(ActionPlugin.class), client, circuitBreakerService, usageService, systemIndices, tracer, clusterService, reservedStateHandlers ); modules.add(actionModule); //restController is stored in networkModule, and NetworkModule is a module used to handle registration and binding of all network-related classes. //There is actionModule.initRestHandlers at the end to initialize the handler final RestController restController = actionModule.getRestController(); final NetworkModule networkModule = new NetworkModule( settings, pluginsService.filterPlugins(NetworkPlugin.class), threadPool, bigArrays, pageCacheRecycler, circuitBreakerService, namedWriteableRegistry, xContentRegistry, networkService, restController, actionModule::copyRequestHeadersToThreadContext, clusterService.getClusterSettings(), tracer ); //Omit code. . . . //Initialize Rest's Handler actionModule.initRestHandlers(() -> clusterService.state().nodesIfRecovered()); }
2. Perform the operation of initializing RestHanders at the end of the node construction object
public void initRestHandlers(Supplier<DiscoveryNodes> nodesInCluster) {<!-- --> //Omit code. . . Here are just a few frequently used ones registerHandler.accept(new RestGetIndicesAction()); registerHandler.accept(new RestIndicesStatsAction()); registerHandler.accept(new RestCreateIndexAction()); registerHandler.accept(new RestDeleteIndexAction()); registerHandler.accept(new RestGetIndexTemplateAction()); registerHandler.accept(new RestPutIndexTemplateAction()); registerHandler.accept(new RestDeleteIndexTemplateAction()); registerHandler.accept(new RestPutMappingAction()); registerHandler.accept(new RestGetMappingAction()); registerHandler.accept(new RestGetFieldMappingAction()); registerHandler.accept(new RestIndexAction()); registerHandler.accept(new RestSearchAction(restController.getSearchUsageHolder())); //Omit code }
3. Take the RestGetIndicesAction object registered in the handler as an example
/** * The REST handler for get index and head index APIs. * REST handlers for the Get Index and Header Index APIs. */ @ServerlessScope(Scope.PUBLIC) public class RestGetIndicesAction extends BaseRestHandler {<!-- --> //Represents routing matching rules. Through this rule, we know that we need to call this instance. The routing rules of each instance are different. @Override public List<Route> routes() {<!-- --> return List.of(new Route(GET, "/{index}"), new Route(HEAD, "/{index}")); } @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {<!-- --> // starting with 7.0 we don't include types by default in the response to GET requests if (request.getRestApiVersion() == RestApiVersion.V_7 & amp; & amp; request.hasParam(INCLUDE_TYPE_NAME_PARAMETER) & amp; & amp; request.method().equals(GET)) {<!-- --> deprecationLogger.compatibleCritical("get_indices_with_types", TYPES_DEPRECATION_MESSAGE); } String[] indices = Strings.splitStringByCommaToArray(request.param("index")); final GetIndexRequest getIndexRequest = new GetIndexRequest(); getIndexRequest.indices(indices); getIndexRequest.indicesOptions(IndicesOptions.fromRequest(request, getIndexRequest.indicesOptions())); getIndexRequest.local(request.paramAsBoolean("local", getIndexRequest.local())); getIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getIndexRequest.masterNodeTimeout())); getIndexRequest.humanReadable(request.paramAsBoolean("human", false)); getIndexRequest.includeDefaults(request.paramAsBoolean("include_defaults", false)); getIndexRequest.features(GetIndexRequest.Feature.fromRequest(request)); final var httpChannel = request.getHttpChannel(); return channel -> new RestCancellableNodeClient(client, httpChannel).admin() .indices() .getIndex(getIndexRequest, new RestChunkedToXContentListener<>(channel)); } }
1. Inherited BaseRestHandler, the routes method is used as routing rules, and the parent class calls the prepareRequest implementation of the subclass
public abstract class BaseRestHandler implements RestHandler {<!-- --> /** * {@inheritDoc} */ @Override public abstract List<Route> routes(); @Override public final void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception {<!-- --> //Call the prepareRequest method to prepare the request for execution and process the request parameters. final RestChannelConsumer action = prepareRequest(request, client); //Filter unused parameters and collect unused parameters into an ordered collection. final SortedSet<String> unconsumedParams = request.unconsumedParams() .stream() .filter(p -> responseParams(request.getRestApiVersion()).contains(p) == false) .collect(Collectors.toCollection(TreeSet::new)); //Verify whether unused parameters are valid. If there are invalid parameters, throw an IllegalArgumentException. if (unconsumedParams.isEmpty() == false) {<!-- --> final Set<String> candidateParams = new HashSet<>(); candidateParams.addAll(request.consumedParams()); candidateParams.addAll(responseParams(request.getRestApiVersion())); throw new IllegalArgumentException(unrecognized(request, unconsumedParams, candidateParams, "parameter")); } //Verify whether the request contains the request body and whether the request body has been consumed. If the conditions are not met, an IllegalArgumentException is thrown. if (request.hasContent() & amp; & amp; request.isContentConsumed() == false) {<!-- --> throw new IllegalArgumentException("request [" + request.method() + " " + request.path() + "] does not support having a body"); } //Increase usage count usageCount.increment(); //Execute the action and pass the result to the channel. action.accept(channel); } /** * Prepare the request for execution. * Implementations should consume all request parameters before returning the runnable object for actual execution. * Unused parameters will immediately terminate the execution of the request. * However, some parameters are used only for handling responses; implementations can override {@link BaseRestHandlerresponseParams()} to indicate such parameters. */ protected abstract RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException; }
2. BaseRestHandler implements the RestHandler interface
/** * Handler for REST requests */ @FunctionalInterface public interface RestHandler {<!-- --> /** * Handle rest requests */ void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception; /** * A list of {@link routes} that this RestHandler is responsible for handling. */ default List<Route> routes() {<!-- --> return Collections.emptyList(); } }
The upstream of handerRequest
that calls the RestHandler
interface is
@Override public void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception {<!-- --> //Requests using the OPTIONS method should be handled elsewhere rather than by calling {@code RestHandlerhandleRequest} HTTP requests using the OPTIONS method bypass authn, so this sanity check prevents unauthenticated requests from being dispatched if (request.method() == Method.OPTIONS) {<!-- --> handleException( request, channel, new ElasticsearchSecurityException("Cannot dispatch OPTIONS request, as they are not authenticated") ); return; } if (enabled == false) {<!-- --> doHandleRequest(request, channel, client); return; } } private void doHandleRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception {<!-- --> threadContext.sanitizeHeaders(); // operator privileges can short circuit to return a non-successful response if (operatorPrivilegesService.checkRest(restHandler, request, channel, threadContext)) {<!-- --> try {<!-- --> restHandler.handleRequest(request, channel, client); } catch (Exception e) {<!-- --> logger.debug(() -> format("Request handling failed for REST request [%s]", request.uri()), e); throw e; } } }
Other APIs registered in hander
are similar to RestGetIndicesAction