diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php b/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php
index 3c6765f..1cdb868 100644
--- a/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php
+++ b/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php
@@ -23,7 +23,7 @@
  *   module = "rest",
  *   title = @Translation("REST export"),
  *   help = @Translation("Create a REST export resource."),
- *   uses_hook_menu = TRUE,
+ *   uses_route = TRUE,
  *   admin = @Translation("REST export")
  * )
  */
diff --git a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterRoleTest.php b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterRoleTest.php
new file mode 100644
index 0000000..2f2f5ed
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterRoleTest.php
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Routing\RouterRoleTest.
+ */
+
+namespace Drupal\system\Tests\Routing;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Defines tests for role based access in routes.
+ */
+class RouterRoleTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('router_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Router Role tests',
+      'description' => 'Function Tests for the routing role system.',
+      'group' => 'Routing',
+    );
+  }
+
+  /**
+   * Tests role requirements on routes.
+   */
+  public function testRoleAccess() {
+
+    // Setup two different roles used in the test.
+    $rid_1 = $this->drupalCreateRole(array(), 'role_test_1');
+    $rid_2 = $this->drupalCreateRole(array(), 'role_test_2');
+
+    // Setup one user with the first role, one with the second, one with both
+    // and one final without any of these two roles.
+    $all_uids = array();
+    $accounts = array();
+    $account_1 = $this->drupalCreateUser();
+    $account_1->roles[$rid_1] = $rid_1;
+    $account_1->save();
+    $all_uids[] = $account_1->id();
+    $accounts[$account_1->id()] = $account_1;
+
+    $account_2 = $this->drupalCreateUser();
+    $account_2->roles[$rid_2] = $rid_2;
+    $account_2->save();
+    $all_uids[] = $account_2->id();
+    $accounts[$account_2->id()] = $account_2;
+
+    $account_12 = $this->drupalCreateUser();
+    $account_12->roles[$rid_1] = $rid_1;
+    $account_12->roles[$rid_2] = $rid_2;
+    $account_12->save();
+    $all_uids[] = $account_12->id();
+    $accounts[$account_12->id()] = $account_12;
+
+    $account_none = $this->drupalCreateUser();
+    $all_uids[] = $account_none->id();
+    $accounts[$account_none->id()] = $account_none;
+
+    // Setup expected values, so which path can be access by which user.
+    $expected = array();
+    $expected['test10'] = array($account_1->id(), $account_12->id());
+    $expected['test11'] = array($account_2->id(), $account_12->id());
+    $expected['test12'] = array($account_12->id());
+    $expected['test13'] = array($account_1->id(), $account_2->id(), $account_12->id(), $account_none->id());
+
+    // @todo Decide whether it's worth to manipulate global $user; and directly
+    // check the access or call the actual pages.
+    foreach ($expected as $path => $uids) {
+      // Login for each user and check the access to the path.
+      foreach ($uids as $uid) {
+        $account = $accounts[$uid];
+        $this->drupalLogin($account);
+        $this->drupalGet('/router_test/' . $path);
+        $this->assertResponse(200, format_string('Access granted for user with the roles %roles on path: %path', array(
+          '%roles' => implode(', ', $account->roles),
+          '%path' => $path,
+        )));
+      }
+      // Check all users which don't have access.
+      foreach (array_diff($all_uids, $uids) as $uid) {
+        $account = $accounts[$uid];
+        $this->drupalLogin($account);
+        $this->drupalGet('/router_test/' . $path);
+        $this->assertResponse(403, format_string('Access denied for user with the roles %roles on path: %path', array(
+          '%roles' => implode(', ', $account->roles),
+          '%path' => $path,
+        )));
+      }
+    }
+
+  }
+
+}
diff --git a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php
index adb5c34..86342d5 100644
--- a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php
+++ b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php
@@ -14,6 +14,10 @@
  */
 class TestControllers {
 
+  public function test() {
+    return new Response('test');
+  }
+
   public function test1() {
     return new Response('test1');
   }
diff --git a/core/modules/system/tests/modules/router_test/router_test.routing.yml b/core/modules/system/tests/modules/router_test/router_test.routing.yml
index 95b0cec..7bae9c0 100644
--- a/core/modules/system/tests/modules/router_test/router_test.routing.yml
+++ b/core/modules/system/tests/modules/router_test/router_test.routing.yml
@@ -53,3 +53,31 @@ router_test_9:
   requirements:
     _permission: 'access test7'
     _access_router_test: 'TRUE'
+
+router_test_10:
+  pattern: '/router_test/test10'
+  defaults:
+    _controller: '\Drupal\router_test\TestControllers::test'
+  requirements:
+    _role_id: 'role_test_1'
+
+router_test_11:
+  pattern: '/router_test/test11'
+  defaults:
+    _controller: '\Drupal\router_test\TestControllers::test'
+  requirements:
+    _role_id: 'role_test_2'
+
+router_test_12:
+  pattern: '/router_test/test12'
+  defaults:
+    _controller: '\Drupal\router_test\TestControllers::test'
+  requirements:
+      _role_id: 'role_test_1, role_test_2'
+
+router_test_13:
+  pattern: '/router_test/test13'
+  defaults:
+    _controller: '\Drupal\router_test\TestControllers::test'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php b/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php
new file mode 100644
index 0000000..02fa2f2
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Access\RoleAccessCheck.
+ */
+
+namespace Drupal\user\Access;
+
+use Drupal\Core\Access\AccessCheckInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Determines access to routes based on roles defined via hook_permission().
+ */
+class RoleAccessCheck implements AccessCheckInterface {
+
+  /**
+   * Implements AccessCheckInterface::applies().
+   */
+  public function applies(Route $route) {
+    return array_key_exists('_role_id', $route->getRequirements());
+  }
+
+  /**
+   * Implements AccessCheckInterface::access().
+   */
+  public function access(Route $route, Request $request) {
+    // Requirements just allow strings, so this might be a comma separated list.
+    $rid_string = $route->getRequirement('_role_id');
+    $rids = array_map('trim', explode(',', $rid_string));
+    // @todo Replace the role check with a correctly injected and session-using
+    //   alternative.
+    $account = $GLOBALS['user'];
+    $roles = array_keys($account->roles);
+
+    $diff = array_diff(array_filter($rids), $roles);
+    if (empty($diff)) {
+      return TRUE;
+    }
+    else {
+      return NULL;
+    }
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/access/Permission.php b/core/modules/user/lib/Drupal/user/Plugin/views/access/Permission.php
index 571a255..2b86872 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/access/Permission.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/access/Permission.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Annotation\Plugin;
 use Drupal\views\Plugin\views\access\AccessPluginBase;
 use Drupal\Core\Annotation\Translation;
+use Symfony\Component\Routing\Route;
 
 /**
  * Access plugin that provides permission-based access control.
@@ -33,8 +34,11 @@ public function access($account) {
     return views_check_perm($this->options['perm'], $account);
   }
 
-  function get_access_callback() {
-    return array('views_check_perm', array($this->options['perm']));
+  /**
+   * Implements \Drupal\views\Plugin\views\access\AccessPluginBase::alterRouteDefinition().
+   */
+  public function alterRouteDefinition(Route $route) {
+    $route->setRequirement('_permission', $this->options['perm']);
   }
 
   public function summaryTitle() {
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php b/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php
index 146968a..40b31bb 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Annotation\Plugin;
 use Drupal\views\Plugin\views\access\AccessPluginBase;
 use Drupal\Core\Annotation\Translation;
+use Symfony\Component\Routing\Route;
 
 /**
  * Access plugin that provides role-based access control.
@@ -29,12 +30,21 @@ class Role extends AccessPluginBase {
    */
   protected $usesOptions = TRUE;
 
+  /**
+   * Implements \Drupal\views\Plugin\views\acecss\AccessPluginBase::access().
+   */
   public function access($account) {
-    return views_check_roles(array_filter($this->options['role']), $account);
+    global $user;
+    $account = isset($account) ? $account : $user;
+    $roles = array_keys($account->roles);
+    return user_access('access all views', $account) || array_intersect(array_filter($this->options['role']), $roles);
   }
 
-  function get_access_callback() {
-    return array('views_check_roles', array(array_filter($this->options['role'])));
+  /**
+   * Implements \Drupal\views\Plugin\views\acecss\AccessPluginBase::alterRouteDefinition().
+   */
+  public function alterRouteDefinition(Route $route) {
+    $route->setRequirement('_role_id', $this->options['role']);
   }
 
   public function summaryTitle() {
diff --git a/core/modules/user/lib/Drupal/user/UserBundle.php b/core/modules/user/lib/Drupal/user/UserBundle.php
index 6cf5f52..ff286cb 100644
--- a/core/modules/user/lib/Drupal/user/UserBundle.php
+++ b/core/modules/user/lib/Drupal/user/UserBundle.php
@@ -24,6 +24,8 @@ public function build(ContainerBuilder $container) {
       ->addTag('access_check');
     $container->register('access_check.user.register', 'Drupal\user\Access\RegisterAccessCheck')
       ->addTag('access_check');
+    $container->register('access_check.user.role', 'Drupal\user\Access\RoleAccessCheck')
+      ->addTag('access_check');
     $container
       ->register('user.data', 'Drupal\user\UserData')
       ->addArgument(new Reference('database'));
diff --git a/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php
new file mode 100644
index 0000000..79f7c84
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\EventSubscriber\RouteSubscriber.
+ */
+
+namespace Drupal\views\EventSubscriber;
+
+use Drupal\Core\Routing\RouteBuildEvent;
+use Drupal\Core\Routing\RoutingEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Defines the routes for a view.
+ */
+class RouteSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Implements \Symfony\Component\EventDispatcher\EventSubscriberInterface::getSubscribedEvents().
+   */
+  public static function getSubscribedEvents() {
+    $events[RoutingEvents::DYNAMIC] = 'dynamicRoutes';
+    return $events;
+  }
+
+  /**
+   * Adds routes defined by all views.
+   *
+   * @param \Drupal\Core\Routing\RouteBuildEvent $event
+   *   The route building event.
+   */
+  public function dynamicRoutes(RouteBuildEvent $event) {
+    $collection = $event->getRouteCollection();
+
+    $views = views_get_applicable_views('uses_route');
+    foreach ($views as $data) {
+      list($view, $display_id) = $data;
+      if ($view->setDisplay($display_id) && $display = $view->displayHandlers->get($display_id)) {
+        $display->collectRoutes($collection);
+      }
+    }
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php
index 0d70b4c..e3f7cf1 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php
@@ -9,13 +9,14 @@
 
 use Drupal\views\Plugin\views\PluginBase;
 use Drupal\views\ViewExecutable;
+use Symfony\Component\Routing\Route;
 
 /**
  * @defgroup views_access_plugins Views access plugins
  * @{
  * The base plugin to handle access to a view.
  *
- * Therefore it primarily has to implement the access and the get_access_callback
+ * Therefore it primarily has to implement the access and the alterRouteDefinition
  * method.
  */
 
@@ -64,19 +65,7 @@ public function summaryTitle() {
    */
   abstract public function access($account);
 
-  /**
-   * Determine the access callback and arguments.
-   *
-   * This information will be embedded in the menu in order to reduce
-   * performance hits during menu item access testing, which happens
-   * a lot.
-   *
-   * @return array
-   *   The first item of the array should be the function to call,and the
-   *   second item should be an array of arguments. The first item may also be
-   *   TRUE (bool only) which will indicate no access control.
-   */
-  abstract function get_access_callback();
+  abstract public function alterRouteDefinition(Route $route);
 
 }
 
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/access/None.php b/core/modules/views/lib/Drupal/views/Plugin/views/access/None.php
index 923598c..9160201 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/access/None.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/access/None.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Annotation\Translation;
 use Drupal\Core\Annotation\Plugin;
+use Symfony\Component\Routing\Route;
 
 /**
  * Access plugin that provides no access control at all.
@@ -36,11 +37,10 @@ public function access($account) {
   }
 
   /**
-   * Implements Drupal\views\Plugin\views\access\AccessPluginBase::get_access_callback().
+   * Implements \Drupal\views\Plugin\views\acecss\AccessPluginBase::alterRouteDefinition().
    */
-  public function get_access_callback() {
-    // No access control.
-    return TRUE;
+  public function alterRouteDefinition(Route $route) {
+    // Don't do anything.
   }
 
 }
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
index bb3fbdf..0ee25e7 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\views\ViewExecutable;
 use \Drupal\views\Plugin\views\PluginBase;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * @defgroup views_display_plugins Views display plugins
@@ -807,6 +808,9 @@ public function getPlugin($type) {
       $plugin = drupal_container()->get("plugin.manager.views.$type")->createInstance($name);
 
       // Initialize the plugin.
+      if ($type == 'access') {
+        debug($options);
+      }
       $plugin->init($this->view, $this, $options['options']);
 
       $this->plugins[$type][$name] = $plugin;
@@ -2408,6 +2412,17 @@ public function renderMoreLink() {
   }
 
   /**
+   * Adds the route entry of a view to the collection.#
+   *
+   * @param \Symfony\Component\Routing\RouteCollection $collection
+   *   A collection of routes that should be registered for this resource.
+   */
+  public function collectRoutes(RouteCollection $collection) {
+
+  }
+
+
+  /**
    * If this display creates a page with a menu item, implement it here.
    *
    * @param array $callbacks
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/Feed.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/Feed.php
index 1fe792d..62d9710 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/Feed.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/Feed.php
@@ -22,7 +22,7 @@
  *   id = "feed",
  *   title = @Translation("Feed"),
  *   help = @Translation("Display the view as a feed, such as an RSS feed."),
- *   uses_hook_menu = TRUE,
+ *   uses_route = TRUE,
  *   admin = @Translation("Feed")
  * )
  */
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/Page.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/Page.php
index f2846c3..ff0d3f5 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/Page.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/Page.php
@@ -22,6 +22,7 @@
  *   title = @Translation("Page"),
  *   help = @Translation("Display the view as a page, with a URL and menu links."),
  *   uses_hook_menu = TRUE,
+ *   uses_route = TRUE,
  *   contextual_links_locations = {"page"},
  *   theme = "views_view",
  *   admin = @Translation("Page")
@@ -92,7 +93,10 @@ public function execute() {
     // And the title, which is much easier.
     drupal_set_title(filter_xss_admin($this->view->getTitle()), PASS_THROUGH);
 
-    return $render;
+    $response = $this->view->getResponse();
+    $response->setContent(drupal_render_page($render));
+
+    return $response;
   }
 
   /**
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
index 8aa9368..83776da 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
@@ -9,6 +9,8 @@
 
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * The base display plugin for path/callbacks. This is used for pages and feeds.
@@ -33,6 +35,62 @@ protected function defineOptions() {
   }
 
   /**
+   * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::collectRoutes().
+   */
+  public function collectRoutes(RouteCollection $collection) {
+    $view_id = $this->view->storage->id();
+    $display_id = $this->display['id'];
+
+    $defaults = array(
+      '_controller' => 'views.page_controller:handle',
+      'view_id' => $view_id,
+      'display_id' => $display_id,
+    );
+
+    // @todo How do we apply argument validation?
+    $bits = explode('/', $this->getOption('path'));
+    // @todo Figure out validation/argument loading.
+    // Replace % with %views_arg for menu autoloading and add to the
+    // page arguments so the argument actually comes through.
+    $arg_counter = 0;
+
+    $this->view->initHandlers();
+    $view_arguments = $this->view->argument;
+    $argument_ids = array_keys($view_arguments);
+    $total_arguments = count($argument_ids);
+    foreach ($bits as &$bit) {
+      if ($bit == '%') {
+        $arg_id = 'arg_' . $argument_ids[$arg_counter++];
+        $defaults[$arg_id] = '';
+        $bit = '{' . $arg_id . '}';
+      }
+    }
+
+    // Add missing arguments not defined in the page settings.
+    while (($total_arguments - $arg_counter) > 0) {
+      $arg_id = 'arg_' . $argument_ids[$arg_counter++];
+      $bit = '{' . $arg_id . '}';
+      $defaults[$arg_id] = '';
+      $bits[] = $bit;
+    }
+
+    $route_path = '/' . implode('/', $bits);
+    debug($route_path);
+
+    $route = new Route($route_path, $defaults);
+
+    // Add access check parameters to the route.
+    $access_plugin = $this->getPlugin('access');
+    if (!isset($access_plugin)) {
+      // @todo Do we want to support a default plugin in getPlugin itself?
+      $access_plugin = drupal_container()->get('plugin.manager.views.access')->createInstance('none');
+    }
+    $access_plugin->alterRouteDefinition($route);
+
+    $collection->add("$view_id.$display_id", $route);
+  }
+
+  /**
    * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::executeHookMenu().
    */
   public function executeHookMenu($callbacks) {
@@ -59,49 +117,15 @@ public function executeHookMenu($callbacks) {
 
     $path = implode('/', $bits);
 
-    $access_plugin = $this->getPlugin('access');
-    if (!isset($access_plugin)) {
-      $access_plugin = drupal_container()->get("plugin.manager.views.access")->createInstance('none');
-    }
-
-    // Get access callback might return an array of the callback + the dynamic
-    // arguments.
-    $access_plugin_callback = $access_plugin->get_access_callback();
-
-    if (is_array($access_plugin_callback)) {
-      $access_arguments = array();
-
-      // Find the plugin arguments.
-      $access_plugin_method = array_shift($access_plugin_callback);
-      $access_plugin_arguments = array_shift($access_plugin_callback);
-      if (!is_array($access_plugin_arguments)) {
-        $access_plugin_arguments = array();
-      }
-
-      $access_arguments[0] = array($access_plugin_method, &$access_plugin_arguments);
-
-      // Move the plugin arguments to the access arguments array.
-      $i = 1;
-      foreach ($access_plugin_arguments as $key => $value) {
-        if (is_int($value)) {
-          $access_arguments[$i] = $value;
-          $access_plugin_arguments[$key] = $i;
-          $i++;
-        }
-      }
-    }
-    else {
-      $access_arguments = array($access_plugin_callback);
-    }
-
     if ($path) {
       $items[$path] = array(
         // Default views page entry.
-        'page callback' => 'views_page',
-        'page arguments' => $page_arguments,
+        // @todo _menu_router_build() denies access to paths without a page
+        //   callback.
+        'page callback' => 'NOT_USED',
+        'page arguments' => array(),
         // Default access check (per display).
-        'access callback' => 'views_access',
-        'access arguments' => $access_arguments,
+        'access callback' => TRUE,
         // Identify URL embedded arguments and correlate them to a handler.
         'load arguments'  => array($this->view->storage->id(), $this->display['id'], '%index'),
       );
@@ -158,8 +182,10 @@ public function executeHookMenu($callbacks) {
             $default_path = implode('/', $bits);
             $items[$default_path] = array(
               // Default views page entry.
-              'page callback' => 'views_page',
-              'page arguments' => $page_arguments,
+              // @todo _menu_router_build() denies access to paths without a page
+              //   callback.
+              'page callback' => 'NOT_USED',
+              'page arguments' => array(),
               // Default access check (per display).
               'access callback' => 'views_access',
               'access arguments' => $access_arguments,
diff --git a/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php b/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php
new file mode 100644
index 0000000..6709180
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Routing\ViewPageController.
+ */
+
+namespace Drupal\views\Routing;
+
+use Drupal\Core\Entity\EntityManager;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+
+class ViewPageController {
+
+  /**
+   * The entity manager to load a view.
+   *
+   * @var \Drupal\Core\Entity\EntityManager
+   */
+  protected $entityManager;
+
+  /**
+   * Constructs a ViewPageController object.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager.
+   */
+  public function __construct(EntityManager $entity_manager) {
+    $this->entityManager = $entity_manager;
+  }
+
+  /**
+   * Handles a response for a view.
+   */
+  public function handle(Request $request) {
+    $view_id = $request->attributes->get('view_id');
+    $display_id = $request->attributes->get('display_id');
+
+    $entities = $this->entityManager->getStorageController('view')->load(array($view_id));
+    $entity = reset($entities);
+    if (empty($entity)) {
+      throw new NotFoundHttpException(format_string('Page controller for view %id requested, but view was not found.', array('%id' => $view_id)));
+    }
+    $view = $entity->get('executable');
+
+    $args = array();
+    foreach (array_keys((array) $view->argument) as $argument_id) {
+      $args[] = $request->attributes->get('arg_' . $argument_id);
+    }
+
+    return $view->executeDisplay($display_id, $args);
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php
index b4c5118..ad825b4 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php
@@ -74,21 +74,19 @@ function testStaticAccessPlugin() {
     $access_plugin = $view->display_handler->getPlugin('access');
 
     $this->assertFalse($access_plugin->access($this->normal_user));
+    $this->drupalGet('test_access_static');
+    $this->assertResponse(403);
 
+    $display = &$view->storage->getDisplay('default');
+    $display['display_options']['access']['options']['access'] = TRUE;
     $access_plugin->options['access'] = TRUE;
-    $this->assertTrue($access_plugin->access($this->normal_user));
+    $view->save();
+    $this->container->get('router.builder')->rebuild();
 
-    // FALSE comes from hook_menu caching.
-    $expected_hook_menu = array(
-      'views_test_data_test_static_access_callback', array(FALSE)
-    );
-    $hook_menu = $view->executeHookMenu('page_1');
-    $this->assertEqual($expected_hook_menu, $hook_menu['test_access_static']['access arguments'][0]);
+    $this->assertTrue($access_plugin->access($this->normal_user));
 
-    $expected_hook_menu = array(
-      'views_test_data_test_static_access_callback', array(TRUE)
-    );
-    $this->assertTrue(views_access($expected_hook_menu));
+    $this->drupalGet('test_access_static');
+    $this->assertResponse(200);
   }
 
   /**
@@ -107,24 +105,23 @@ function testDynamicAccessPlugin() {
     $access_plugin = $view->display_handler->getPlugin('access');
 
     $this->assertFalse($access_plugin->access($this->normal_user));
+    $this->drupalGet('test_access_dynamic');
+    $this->assertResponse(403);
 
+    $display = &$view->storage->getDisplay('default');
+    $display['display_options']['access']['options']['access'] = TRUE;
     $access_plugin->options['access'] = TRUE;
+    $view->save();
+    $this->container->get('router.builder')->rebuild();
+
     $this->assertFalse($access_plugin->access($this->normal_user));
+    $this->drupalGet("test_access_dynamic");
+    $this->assertResponse(403);
 
     $view->setArguments(array($argument1, $argument2));
     $this->assertTrue($access_plugin->access($this->normal_user));
-
-    // FALSE comes from hook_menu caching.
-    $expected_hook_menu = array(
-      'views_test_data_test_dynamic_access_callback', array(FALSE, 1, 2)
-    );
-    $hook_menu = $view->executeHookMenu('page_1');
-    $this->assertEqual($expected_hook_menu, $hook_menu['test_access_dynamic']['access arguments'][0]);
-
-    $expected_hook_menu = array(
-      'views_test_data_test_dynamic_access_callback', array(TRUE, 1, 2)
-    );
-    $this->assertTrue(views_access($expected_hook_menu, $argument1, $argument2));
+    $this->drupalGet("test_access_dynamic/$argument1/$argument2");
+    $this->assertResponse(200);
   }
 
 }
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php
index 49ed01c..faebcc3 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php
@@ -7,21 +7,40 @@
 
 namespace Drupal\views\Tests\Plugin;
 
-use Drupal\views\Tests\Plugin\PluginTestBase;
+use Drupal\Core\Routing\RouteBuildEvent;
+use Drupal\views\EventSubscriber\RouteSubscriber;
+use Drupal\views\Tests\ViewUnitTestBase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * Tests the page display plugin.
  *
  * @see Drupal\views\Plugin\display\Page
  */
-class DisplayPageTest extends PluginTestBase {
+class DisplayPageTest extends ViewUnitTestBase {
 
   /**
    * Views used by this test.
    *
    * @var array
    */
-  public static $testViews = array('test_page_display');
+  public static $testViews = array('test_page_display', 'test_page_display_route');
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system');
+
+  /**
+   * The router dumper to get all routes.
+   *
+   * @var \Drupal\Core\Routing\MatcherDumper
+   */
+  protected $routerDumper;
 
   public static function getInfo() {
     return array(
@@ -34,18 +53,62 @@ public static function getInfo() {
   protected function setUp() {
     parent::setUp();
 
-    $this->enableViewsTestModule();
+    // Setup the needed tables in order to make the drupal router working.
+    $this->installSchema('system', 'router');
+    $this->installSchema('system', 'url_alias');
+    $this->installSchema('system', 'menu_router');
   }
 
   /**
    * Checks the behavior of the page for access denied/not found behaviours.
    */
   public function testPageResponses() {
-    $view = views_get_view('test_page_display');
-    $this->drupalGet('test_page_display_403');
-    $this->assertResponse(403);
-    $this->drupalGet('test_page_display_404');
-    $this->assertResponse(404);
+    // @todo Importing a route should fire a container rebuild.
+    $this->container->get('router.builder')->rebuild();
+
+    $subrequest = Request::create('/test_page_display_403', 'GET');
+    $response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
+    $this->assertEqual($response->getStatusCode(), 403);
+
+    $subrequest = Request::create('/test_page_display_404', 'GET');
+    $response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
+    $this->assertEqual($response->getStatusCode(), 404);
+
+    $subrequest = Request::create('/test_page_display_200', 'GET');
+    $response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
+    $this->assertEqual($response->getStatusCode(), 200);
+  }
+
+  /**
+   * Checks that the router items are properly registered
+   */
+  public function testPageRouterItems() {
+    $subscriber = new RouteSubscriber();
+    $collection = new RouteCollection();
+    $subscriber->dynamicRoutes(new RouteBuildEvent($collection, 'dynamic_routes'));
+
+    // Check the controller defaults.
+    foreach ($collection as $id => $route) {
+      if (strpos($id, 'test_page_display_route') === 0) {
+        $this->assertEqual($route->getDefault('_controller'), 'views.page_controller:handle');
+        $this->assertEqual($route->getDefault('view_id'), 'test_page_display_route');
+        $this->assertEqual($route->getDefault('display_id'), str_replace('test_page_display_route.', '', $id));
+      }
+    }
+
+    // Check the generated patterns.
+    $this->assertEqual($collection->get('test_page_display_route.page_1')->getPath(), '/test_route_without_arguments');
+    $this->assertEqual($collection->get('test_page_display_route.page_2')->getPath(), '/test_route_with_argument/{arg0}');
+    $this->assertEqual($collection->get('test_page_display_route.page_3')->getPath(), '/test_route_with_argument/{arg0}/suffix');
+    $this->assertEqual($collection->get('test_page_display_route.page_4')->getPath(), '/test_route_with_argument/{arg0}/suffix/{arg1}');
+    $this->assertEqual($collection->get('test_page_display_route.page_5')->getPath(), '/test_route_with_argument/{arg0}/{arg1}');
+    $this->assertEqual($collection->get('test_page_display_route.page_6')->getPath(), '/test_route_with_argument/{arg0}/{arg1}');
+
+    // Check the access callbacks/arguments arguments.
+    $this->assertNull($collection->get('test_page_display_route.page_1')->getOption('_access_callback'));
+    $this->assertNull($collection->get('test_page_display_route.page_1')->getOption('_access_arguments'));
+    $this->assertEqual($collection->get('test_page_display_route.page_7')->getOption('_access_callback'), 'views_test_data_test_static_access_callback');
+    $this->assertIdentical($collection->get('test_page_display_route.page_7')->getOption('_access_arguments'), array(FALSE));
   }
 
 }
diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php
new file mode 100644
index 0000000..6560ac6
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Tests\ViewPageControllerTest.
+ */
+
+namespace Drupal\views\Tests;
+
+use Drupal\views\Routing\ViewPageController;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+
+/**
+ * Tests the page controller but not the actualy execution/rendering of a view.
+ *
+ * @see \Drupal\views\ViewPageController
+ */
+class ViewPageControllerTest extends ViewUnitTestBase {
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = array('test_page_view');
+
+  /**
+   * The page controller of views.
+   *
+   * @var \Drupal\views\ViewPageController
+   */
+  public $pageController;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'View page controller test',
+      'description' => 'Tests views page controller.',
+      'group' => 'Views'
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->pageController = $this->container->get('views.page_controller');
+  }
+
+  /**
+   * Tests the page controller.
+   */
+  public function testPageController() {
+    $this->assertTrue($this->pageController instanceof ViewPageController, 'Ensure the right class is stored in the container');
+
+    // Pass in a non existent view.
+    $random_view_id = $this->randomName();
+
+    $request = new Request();
+    $request->attributes->set('view_id', $random_view_id);
+    $request->attributes->set('display_id', 'default');
+    try {
+      $this->pageController->handle($request);
+      $this->fail('No exception thrown on non-existing view.');
+    }
+
+    catch (NotFoundHttpException $e) {
+      $this->pass('Exception thrown when view was not found');
+    }
+
+    $request->attributes->set('view_id', 'test_page_view');
+    $output = $this->pageController->handle($request);
+    $this->assertTrue(is_array($output));
+    $this->assertEqual($output['#view']->storage->id, 'test_page_view', 'The right view was executed.');
+
+    $request->attributes->set('display_id', 'page_1');
+    $output = $this->pageController->handle($request);
+    $this->assertTrue($output instanceof Response, 'Ensure the page display returns a response object.');
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/ViewExecutable.php b/core/modules/views/lib/Drupal/views/ViewExecutable.php
index 898503f..0755808 100644
--- a/core/modules/views/lib/Drupal/views/ViewExecutable.php
+++ b/core/modules/views/lib/Drupal/views/ViewExecutable.php
@@ -9,6 +9,7 @@
 
 use Symfony\Component\HttpFoundation\Response;
 use Drupal\views\Plugin\Core\Entity\View;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * @defgroup views_objects Objects that represent a View or part of a view
diff --git a/core/modules/views/lib/Drupal/views/ViewsAccessCheck.php b/core/modules/views/lib/Drupal/views/ViewsAccessCheck.php
new file mode 100644
index 0000000..b4c7739
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/ViewsAccessCheck.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\ViewsAccessCheck.
+ */
+
+namespace Drupal\views;
+
+use Drupal\Core\Access\AccessCheckInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Defines a route access checker for the _access_all_views permission.
+ *
+ * @todo We could leverage the permission one as well?
+ */
+class ViewsAccessCheck implements AccessCheckInterface {
+
+  /**
+   * Implements AccessCheckInterface::applies().
+   */
+  public function applies(Route $route) {
+    return $route->getRequirement('_access_all_views');
+  }
+
+  /**
+   * Implements AccessCheckInterface::applies().
+   */
+  public function access(Route $route, Request $request) {
+    $access = user_access('access all views');
+
+    return $access ?: NULL;
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/ViewsBundle.php b/core/modules/views/lib/Drupal/views/ViewsBundle.php
index ac035cb..5f4af2b 100644
--- a/core/modules/views/lib/Drupal/views/ViewsBundle.php
+++ b/core/modules/views/lib/Drupal/views/ViewsBundle.php
@@ -40,6 +40,16 @@ public function build(ContainerBuilder $container) {
 
     $container->register('views.analyzer', 'Drupal\views\Analyzer')
       ->addArgument(new Reference('module_handler'));
+
+    $container->register('views.page_controller', 'Drupal\views\Routing\ViewPageController')
+      ->addArgument(new Reference('plugin.manager.entity'));
+
+    $container->register('views.route_subscriber', 'Drupal\views\EventSubscriber\RouteSubscriber')
+      ->addArgument(new Reference('config.factory'))
+      ->addTag('event_subscriber');
+
+    $container->register('views.route_access_check', 'Drupal\views\ViewsAccessCheck')
+      ->addTag('access_check');
   }
 
 }
diff --git a/core/modules/views/tests/views_test_config/test_views/views.view.test_access_dynamic.yml b/core/modules/views/tests/views_test_config/test_views/views.view.test_access_dynamic.yml
index 6886b90..8ebb8a4 100644
--- a/core/modules/views/tests/views_test_config/test_views/views.view.test_access_dynamic.yml
+++ b/core/modules/views/tests/views_test_config/test_views/views.view.test_access_dynamic.yml
@@ -1,4 +1,4 @@
-base_table: node
+base_table: views_test_data
 core: '8'
 description: ''
 status: '1'
@@ -17,6 +17,17 @@ display:
         type: default
       row:
         type: fields
+      arguments:
+        name:
+          id: name
+          table: views_test_data
+          field: name
+          plugin_id: string
+        name_2:
+          id: name_2
+          table: views_test_data
+          field: name
+          plugin_id: string
     display_plugin: default
     display_title: Master
     id: default
diff --git a/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display.yml b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display.yml
index 3256666..25968f5 100644
--- a/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display.yml
+++ b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display.yml
@@ -1,14 +1,22 @@
-base_table: node
+base_table: views_test_data
 core: '8'
 description: ''
 status: '1'
 display:
   default:
     display_options:
-      access:
-        type: none
-      cache:
-        type: none
+      defaults:
+        fields: '0'
+        pager: '0'
+        pager_options: '0'
+        sorts: '0'
+      fields:
+        age:
+          field: age
+          id: age
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
     display_plugin: default
     display_title: Master
     id: default
@@ -27,6 +35,13 @@ display:
     display_title: Page
     id: page_2
     position: '0'
+  page_3:
+    display_options:
+      path: test_page_display_200
+    display_plugin: page
+    display_title: Page
+    id: page_3
+    position: '0'
 human_name: ''
 id: test_page_display
 tag: ''
diff --git a/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display_route.yml b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display_route.yml
new file mode 100644
index 0000000..6068ad4
--- /dev/null
+++ b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display_route.yml
@@ -0,0 +1,135 @@
+base_table: views_test_data
+core: '8'
+description: ''
+status: '1'
+display:
+  default:
+    display_options:
+      defaults:
+        fields: '0'
+        pager: '0'
+        pager_options: '0'
+        sorts: '0'
+    display_plugin: default
+    display_title: Master
+    id: default
+    position: '0'
+  page_1:
+    display_options:
+      path: test_route_without_arguments
+    display_plugin: page
+    display_title: Page
+    id: page_1
+    position: '0'
+  page_2:
+    display_options:
+      defaults:
+        arguments: '0'
+      arguments:
+        id:
+          field: id
+          id: id
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+      path: test_route_with_argument
+    display_plugin: page
+    display_title: Page
+    id: page_2
+    position: '0'
+  page_3:
+    display_options:
+      defaults:
+        arguments: '0'
+      arguments:
+        id:
+          field: id
+          id: id
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+      path: test_route_with_argument/%/suffix
+    display_plugin: page
+    display_title: Page
+    id: page_3
+    position: '0'
+  page_4:
+    display_options:
+      defaults:
+        arguments: '0'
+      arguments:
+        id:
+          field: id
+          id: id
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+        id_2:
+          field: id
+          id: id_2
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+      path: test_route_with_argument/%/suffix
+    display_plugin: page
+    display_title: Page
+    id: page_4
+    position: '0'
+  page_5:
+    display_options:
+      defaults:
+        arguments: '0'
+      arguments:
+        id:
+          field: id
+          id: id
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+        id_2:
+          field: id
+          id: id_2
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+      path: test_route_with_argument
+    display_plugin: page
+    display_title: Page
+    id: page_5
+    position: '0'
+  page_6:
+    display_options:
+      defaults:
+        arguments: '0'
+      arguments:
+        id:
+          field: id
+          id: id
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+        id_2:
+          field: id
+          id: id_2
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+      path: test_route_with_argument/%/%
+    display_plugin: page
+    display_title: Page
+    id: page_6
+    position: '0'
+  page_7:
+    display_options:
+      defaults:
+        access: '0'
+      access:
+        type: test_static
+      path: test_route_arguments_access
+    display_plugin: page
+    display_title: Page
+    id: page_7
+    position: '0'
+human_name: ''
+id: test_page_display_route
+tag: ''
diff --git a/core/modules/views/tests/views_test_config/test_views/views.view.test_page_view.yml b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_view.yml
new file mode 100644
index 0000000..41d09e5
--- /dev/null
+++ b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_view.yml
@@ -0,0 +1,30 @@
+base_table: views_test_data
+core: '8'
+description: ''
+disabled: '0'
+display:
+  default:
+    display_options:
+      defaults:
+        fields: '0'
+        pager: '0'
+        pager_options: '0'
+        sorts: '0'
+      fields:
+        age:
+          field: age
+          id: age
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+    display_plugin: default
+    display_title: Master
+    id: default
+    position: '0'
+  page_1:
+    display_plugin: page
+    display_title: Test page view
+    id: page_1
+human_name: ''
+id: test_page_view
+tag: ''
diff --git a/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Access/DynamicTestAccessCheck.php b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Access/DynamicTestAccessCheck.php
new file mode 100644
index 0000000..1b744ed
--- /dev/null
+++ b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Access/DynamicTestAccessCheck.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views_test_data\Access\DynamicTestAccessCheck.
+ */
+
+namespace Drupal\views_test_data\Access;
+
+use Drupal\Core\Access\AccessCheckInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Defines a access checker for views tests.
+ */
+class DynamicTestAccessCheck implements AccessCheckInterface {
+
+  /**
+   * Implements AccessCheckInterface::applies().
+   */
+  public function applies(Route $route) {
+    return array_key_exists('_dynamic_test', $route->getRequirements());
+  }
+
+  /**
+   * Implements AccessCheckInterface::access().
+   */
+  public function access(Route $route, Request $request) {
+    $access = $route->getRequirement('_dynamic_test');
+    $argument1 = $request->attributes->get('arg_0');
+    $argument2 = $request->attributes->get('arg_1');
+
+    return $access && $argument1 == state()->get('test_dynamic_access_argument1') && $argument2 == state()->get('test_dynamic_access_argument2');
+  }
+
+}
diff --git a/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/DynamicTest.php b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/DynamicTest.php
index d8d0b83..e24602d 100644
--- a/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/DynamicTest.php
+++ b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/DynamicTest.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Annotation\Plugin;
 use Drupal\Core\Annotation\Translation;
 use Drupal\views\Plugin\views\access\AccessPluginBase;
+use Symfony\Component\Routing\Route;
 
 /**
  * Tests a dynamic access plugin.
@@ -33,8 +34,13 @@ public function access($account) {
     return !empty($this->options['access']) && isset($this->view->args[0]) && $this->view->args[0] == state()->get('test_dynamic_access_argument1') && isset($this->view->args[1]) && $this->view->args[1] == state()->get('test_dynamic_access_argument2');
   }
 
-  function get_access_callback() {
-    return array('views_test_data_test_dynamic_access_callback', array(!empty($options['access']), 1, 2));
+  /**
+   * Implements \Drupal\views\Plugin\views\acecss\AccessPluginBase::alterRouteDefinition().
+   */
+  public function alterRouteDefinition(Route $route) {
+    if ($this->options['access']) {
+      $route->setRequirement('_dynamic_test', (string) $this->options['access']);
+    }
   }
 
 }
diff --git a/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/StaticTest.php b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/StaticTest.php
index 5f5770c..159affc 100644
--- a/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/StaticTest.php
+++ b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/StaticTest.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Annotation\Plugin;
 use Drupal\Core\Annotation\Translation;
 use Drupal\views\Plugin\views\access\AccessPluginBase;
+use Symfony\Component\Routing\Route;
 
 /**
  * Tests a static access plugin.
@@ -33,8 +34,13 @@ public function access($account) {
     return !empty($this->options['access']);
   }
 
-  function get_access_callback() {
-    return array('views_test_data_test_static_access_callback', array(!empty($options['access'])));
+  /**
+   * Implements \Drupal\views\Plugin\views\acecss\AccessPluginBase::alterRouteDefinition().
+   */
+  public function alterRouteDefinition(Route $route) {
+    if (!empty($this->options['access'])) {
+      $route->setRequirement('_access', 'TRUE');
+    }
   }
 
 }
diff --git a/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/ViewsTestDataBundle.php b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/ViewsTestDataBundle.php
new file mode 100644
index 0000000..3c8dbab
--- /dev/null
+++ b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/ViewsTestDataBundle.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views_test_data\ViewsTestDataBundle.
+ */
+
+namespace Drupal\views_test_data;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Alters the Dependency inbjection container for the views_test_data module.
+ */
+
+class ViewsTestDataBundle extends Bundle {
+
+  /**
+   * Overrides \Symfony\Component\HttpKernel\Bundle\Bundle::build().
+   */
+  public function build(ContainerBuilder $container) {
+    $container->register('views_test_data.access_check_dynamic', 'Drupal\views_test_data\Access\DynamicTestAccessCheck')
+      ->addTag('access_check');
+  }
+
+}
diff --git a/core/modules/views/tests/views_test_data/views_test_data.module b/core/modules/views/tests/views_test_data/views_test_data.module
index 40467c6..55fe4f7 100644
--- a/core/modules/views/tests/views_test_data/views_test_data.module
+++ b/core/modules/views/tests/views_test_data/views_test_data.module
@@ -19,14 +19,6 @@ function views_test_data_permission() {
   );
 }
 
-function views_test_data_test_static_access_callback($access) {
-  return $access;
-}
-
-function views_test_data_test_dynamic_access_callback($access, $argument1, $argument2) {
-  return $access && $argument1 == state()->get('test_dynamic_access_argument1') && $argument2 == state()->get('test_dynamic_access_argument2');
-}
-
 /**
  * Access callback for the generic handler test.
  *
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 8dc5f5a..87b6189 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -359,8 +359,8 @@ function views_menu_alter(&$callbacks) {
           // This item already exists, so it must be one that we added.
           // We change the various callback arguments to pass an array
           // of possible display IDs instead of a single ID.
-          $callbacks[$path]['page arguments'][1] = (array)$callbacks[$path]['page arguments'][1];
-          $callbacks[$path]['page arguments'][1][] = $display_id;
+          // $callbacks[$path]['page arguments'][1] = (array)$callbacks[$path]['page arguments'][1];
+          // $callbacks[$path]['page arguments'][1][] = $display_id;
           $callbacks[$path]['access arguments'][] = $item['access arguments'][0];
           $callbacks[$path]['load arguments'][1] = (array)$callbacks[$path]['load arguments'][1];
           $callbacks[$path]['load arguments'][1][] = $display_id;
@@ -695,6 +695,12 @@ function views_invalidate_cache() {
   // Set the menu as needed to be rebuilt.
   state()->set('menu_rebuild_needed', TRUE);
 
+  // Set the router to be rebuild.
+  // @todo This isn't a good fix.
+  if (db_table_exists('router')) {
+    drupal_container()->get('router.builder')->rebuild();
+  }
+
   // Invalidate the block cache to update views block derivatives.
   if (module_exists('block')) {
     drupal_container()->get('plugin.manager.block')->clearCachedDefinitions();
@@ -705,68 +711,6 @@ function views_invalidate_cache() {
 }
 
 /**
- * Determine if the logged in user has access to a view.
- *
- * This function should only be called from a menu hook or some other
- * embedded source. Each argument is the result of a call to
- * views_plugin_access::get_access_callback() which is then used
- * to determine if that display is accessible. If *any* argument
- * is accessible, then the view is accessible.
- */
-function views_access() {
-  $args = func_get_args();
-  foreach ($args as $arg) {
-    if ($arg === TRUE) {
-      return TRUE;
-    }
-
-    if (!is_array($arg)) {
-      continue;
-    }
-
-    list($callback, $arguments) = $arg;
-    $arguments = $arguments ? $arguments : array();
-    // Bring dynamic arguments to the access callback.
-    foreach ($arguments as $key => $value) {
-      if (is_int($value) && isset($args[$value])) {
-        $arguments[$key] = $args[$value];
-      }
-    }
-    if (function_exists($callback) && call_user_func_array($callback, $arguments)) {
-      return TRUE;
-    }
-  }
-
-  return FALSE;
-}
-
-/**
- * Access callback for the views_plugin_access_perm access plugin.
- *
- * Determine if the specified user has access to a view on the basis of
- * permissions. If the $account argument is omitted, the current user
- * is used.
- */
-function views_check_perm($perm, $account = NULL) {
-  return user_access($perm, $account) || user_access('access all views', $account);
-}
-
-/**
- * Access callback for the views_plugin_access_role access plugin.
-
- * Determine if the specified user has access to a view on the basis of any of
- * the requested roles. If the $account argument is omitted, the current user
- * is used.
- */
-function views_check_roles($rids, $account = NULL) {
-  global $user;
-  $account = isset($account) ? $account : $user;
-  $roles = array_keys($account->roles);
-  $roles[] = $account->uid ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID;
-  return user_access('access all views', $account) || array_intersect(array_filter($rids), $roles);
-}
-
-/**
  * Set the current 'page view' that is being displayed so that it is easy
  * for other modules or the theme to identify.
  */
