diff --git a/core/modules/system/lib/Drupal/system/Access/SystemAccessCheck.php b/core/modules/system/lib/Drupal/system/Access/SystemAccessCheck.php
new file mode 100644
index 0000000..629d646
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Access/SystemAccessCheck.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\system\Access\SystemAccessCheck.
+ */
+
+namespace Drupal\system\Access;
+
+use Drupal\Core\Access\AccessCheckInterface;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Access check for system routes.
+ */
+class SystemAccessCheck implements AccessCheckInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applies(Route $route) {
+    return array_key_exists('_access_system_plugin_autocomplete', $route->getRequirements());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access(Route $route, Request $request) {
+    // Checks access for a given plugin using the plugin's access() method.
+    $plugin_ui = \Drupal::service('plugin.manager.system.plugin_ui')->createInstance($request->attributes->get('plugin_id'));
+    return $plugin_ui->access(NULL);
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Controller/SystemController.php b/core/modules/system/lib/Drupal/system/Controller/SystemController.php
new file mode 100644
index 0000000..61379c0
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Controller/SystemController.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Controller\SystemController.
+ */
+
+namespace Drupal\system\Controller;
+
+use Drupal\Core\ControllerInterface;
+use Drupal\system\Plugin\Type\PluginUIManager;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\JsonResponse;
+
+
+/**
+ * Returns responses for System routes.
+ */
+class SystemController implements ControllerInterface {
+
+  /**
+   * The plugin UI manager.
+   *
+   * @var \Drupal\system\Plugin\Type\PluginUIManager
+   */
+  protected $pluginUiManager;
+
+  /**
+   * Constructs a SystemController object.
+   *
+   * @param \Drupal\system\Plugin\Type\PluginUIManager $plugin_ui_manager
+   *   The plugin UI manager.
+   */
+  public function __construct(PluginUIManager $plugin_ui_manager) {
+    $this->pluginUiManager = $plugin_ui_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.system.plugin_ui')
+    );
+  }
+
+  /**
+   * Autocompletes any plugin system tied to a plugin UI plugin.
+   *
+   * The passed plugin_id indicates the specific plugin_ui plugin that is in use
+   * here. The documentation within the annotation of that plugin will contain a
+   * manager for the plugins that need to be autocompleted allowing this
+   * function to autocomplete plugins for any plugin type.
+   *
+   * @param string $plugin_id
+   *   The plugin id for the calling plugin.
+   * @param Request $request
+   *   The request object that contains the typed tags.
+   *
+   * @return \Symfony\Component\HttpFoundation\JsonResponse
+   *   The matched plugins as json.
+   */
+  public function autocomplete($plugin_id, Request $request) {
+    $string_typed = $request->query->get('q');
+    $string_typed = drupal_explode_tags($string_typed);
+    $string = drupal_strtolower(array_pop($string_typed));
+    $matches = array();
+    if ($string) {
+      $plugin_ui = $this->pluginUiManager->getDefinition($plugin_id);
+      $manager = \Drupal::service($plugin_ui['manager']);
+      $titles = array();
+      foreach($manager->getDefinitions() as $plugin_id => $plugin) {
+        $titles[$plugin_id] = $plugin[$plugin_ui['title_attribute']];
+      }
+      $matches = preg_grep("/\b". $string . "/i", $titles);
+    }
+
+    return new JsonResponse($matches);
+  }
+
+}
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index f8d4482..2456dff 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1046,10 +1046,7 @@ function system_menu() {
         }
       }
       $items['system/autocomplete/' . $plugin_id] = array(
-        'page callback' => 'system_plugin_autocomplete',
-        'page arguments' => array($plugin_id),
-        'access callback' => 'system_plugin_ui_access',
-        'access arguments' => array($plugin_id),
+        'route_name' => 'system_plugin_autocomplete',
         'type' => MENU_CALLBACK,
       );
     }
@@ -1073,37 +1070,6 @@ function system_plugin_ui_form($form, &$form_state, $plugin, $facet = NULL) {
 }
 
 /**
- * Page callback: Autocompletes any plugin system tied to a plugin UI plugin.
- *
- * The passed plugin_id indicates the specific plugin_ui plugin that is in use
- * here. The documentation within the annotation of that plugin will contain a
- * manager for the plugins that need to be autocompleted allowing this function
- * to autocomplete plugins for any plugin type.
- *
- * @param $plugin_id
- *   The plugin id for the calling plugin.
- *
- * @return object JsonResponse
- */
-function system_plugin_autocomplete($plugin_id) {
-  $string_typed = drupal_container()->get('request')->query->get('q');
-  $string_typed = drupal_explode_tags($string_typed);
-  $string = drupal_strtolower(array_pop($string_typed));
-  $matches = array();
-  if ($string) {
-    $plugin_ui = Drupal::service('plugin.manager.system.plugin_ui')->getDefinition($plugin_id);
-    $manager = Drupal::service($plugin_ui['manager']);
-    $titles = array();
-    foreach($manager->getDefinitions() as $plugin_id => $plugin) {
-      $titles[$plugin_id] = $plugin[$plugin_ui['title_attribute']];
-    }
-    $matches = preg_grep("/\b". $string . "/i", $titles);
-  }
-
-  return new JsonResponse($matches);
-}
-
-/**
  * Checks access for a given plugin using the plugin's access() method.
  *
  * @todo This needs more explanation, some @see, and parameter documentation.
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index 6f0e7f5..c1a1779 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -137,3 +137,9 @@ system_php:
   requirements:
     _permission: 'administer site configuration'
 
+system_plugin_autocomplete:
+  pattern: '/system/autocomplete/{plugin_id}'
+  defaults:
+    _controller: 'Drupal\system\Controller\SystemController::autocomplete'
+  requirements:
+    _access_system_plugin_autocomplete: 'TRUE'
diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml
index 8f0d232..7db1267 100644
--- a/core/modules/system/system.services.yml
+++ b/core/modules/system/system.services.yml
@@ -3,6 +3,10 @@ services:
     class: Drupal\system\Access\CronAccessCheck
     tags:
       - { name: access_check }
+  access_check.system:
+    class: Drupal\system\Access\SystemAccessCheck
+    tags:
+      - { name: access_check }
   plugin.manager.system.plugin_ui:
     class: Drupal\system\Plugin\Type\PluginUIManager
     arguments: ['@container.namespaces']
