diff --git a/core/core.services.yml b/core/core.services.yml
index a9b8c3e..7c9c777 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -205,7 +205,7 @@ services:
     arguments: ['@container.namespaces', '@cache.discovery', '@language_manager', '@module_handler']
   module_handler:
     class: Drupal\Core\Extension\ModuleHandler
-    arguments: ['%container.modules%', '@cache.bootstrap']
+    arguments: ['%container.modules%', '@cache.bootstrap', '@event_dispatcher']
   theme_handler:
     class: Drupal\Core\Extension\ThemeHandler
     arguments: ['@config.factory', '@module_handler', '@state', '@info_parser', '@config.installer', '@router.builder']
@@ -244,6 +244,8 @@ services:
     arguments: ['@controller_resolver', '@module_handler', '@cache.discovery', '@language_manager', '@access_manager', '@current_user', '@request_stack']
   plugin.cache_clearer:
     class: Drupal\Core\Plugin\CachedDiscoveryClearer
+    tags:
+      - { name: 'event_subscriber' }
   request:
     class: Symfony\Component\HttpFoundation\Request
     synthetic: true
@@ -761,6 +763,11 @@ services:
     arguments: ['@request_stack', '@database']
     tags:
       - { name: persist }
+  module_handler_subscriber:
+    class: Drupal\Core\EventSubscriber\ModuleHandlerSubscriber
+    arguments: ['@request_stack', '@database']
+    tags:
+      - { name: event_subscriber }
   asset.css.collection_renderer:
     class: Drupal\Core\Asset\CssCollectionRenderer
     arguments: [ '@state' ]
diff --git a/core/lib/Drupal/Core/EventSubscriber/ModuleHandlerSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ModuleHandlerSubscriber.php
new file mode 100644
index 0000000..aedfa30
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/ModuleHandlerSubscriber.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\EventSubscriber\ModuleHandlerSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ExtensionEvent;
+use Drupal\Core\Extension\ModuleEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Yaml\Parser;
+
+/**
+ * Core module handler subscriber.
+ */
+class ModuleHandlerSubscriber implements EventSubscriberInterface {
+
+  /**
+   * @param ExtensionEvent $event
+   * @param $event_name
+   */
+  public function onModuleUninstall(ExtensionEvent $event) {
+    // Remove any potential cache bins provided by the module.
+    $this->removeCacheBins($event->getExtension());
+  }
+
+  /**
+   * Helper method for removing all cache bins registered by a given module.
+   *
+   * @param string $module
+   *   The name of the module for which to remove all registered cache bins.
+   */
+  protected function removeCacheBins($module) {
+    // Remove any cache bins defined by a module.
+    $service_yaml_file = drupal_get_path('module', $module) . "/$module.services.yml";
+    if (file_exists($service_yaml_file)) {
+      $parser = new Parser;
+      $definitions = $parser->parse(file_get_contents($service_yaml_file));
+      if (isset($definitions['services'])) {
+        foreach ($definitions['services'] as $id => $definition) {
+          if (isset($definition['tags'])) {
+            foreach ($definition['tags'] as $tag) {
+              // This works for the default cache registration and even in some
+              // cases when a non-default "super" factory is used. That should
+              // be extremely rare.
+              if ($tag['name'] == 'cache.bin' && isset($definition['factory_service']) && isset($definition['factory_method']) && !empty($definition['arguments'])) {
+                try {
+                  $factory = \Drupal::service($definition['factory_service']);
+                  if (method_exists($factory, $definition['factory_method'])) {
+                    $backend = call_user_func_array(array($factory, $definition['factory_method']), $definition['arguments']);
+                    if ($backend instanceof CacheBackendInterface) {
+                      $backend->removeBin();
+                    }
+                  }
+                }
+                catch (\Exception $e) {
+                  watchdog_exception('system', $e, 'Failed to remove cache bin defined by the service %id.', array('%id' => $id));
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  static function getSubscribedEvents() {
+    $events[ModuleEvents::UNINSTALL][] = array('onModuleUninstall');
+    return $events;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Extension/CachedModuleHandler.php b/core/lib/Drupal/Core/Extension/CachedModuleHandler.php
new file mode 100644
index 0000000..1594d86
--- /dev/null
+++ b/core/lib/Drupal/Core/Extension/CachedModuleHandler.php
@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Extension\CachedModuleHandler.
+ */
+
+namespace Drupal\Core\Extension;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\KeyValueStore\StateInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+
+/**
+ * Class that manages enabled modules in a Drupal installation.
+ */
+class CachedModuleHandler extends ModuleHandler implements CachedModuleHandlerInterface {
+
+  /**
+   * State key/value store.
+   *
+   * @var \Drupal\Core\KeyValueStore\StateInterface
+   */
+  protected $state;
+
+  /**
+   * Cache backend for storing enabled modules.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $bootstrapCache;
+
+  /**
+   * Whether the cache needs to be written.
+   *
+   * @var boolean
+   */
+  protected $cacheNeedsWriting = FALSE;
+
+  /**
+   * Constructs a new CachedModuleHandler object.
+   */
+  public function __construct(array $module_list = array(), StateInterface $state, CacheBackendInterface $bootstrap_cache, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct($module_list, $event_dispatcher);
+
+    $this->state = $state;
+    $this->bootstrapCache = $bootstrap_cache;
+  }
+
+  /**
+   * Overrides \Drupal\Core\Extension\ModuleHandler::getHookInfo().
+   */
+  public function getHookInfo() {
+    // When this function is indirectly invoked from bootstrap_invoke_all() prior
+    // to all modules being loaded, we do not want to cache an incomplete
+    // hook_hookInfo() result, so instead return an empty array. This requires
+    // bootstrap hook implementations to reside in the .module file, which is
+    // optimal for performance anyway.
+    if (!$this->loaded) {
+      return array();
+    }
+    if (!isset($this->hookInfo)) {
+      if ($cache = $this->bootstrapCache->get('hook_info')) {
+        $this->hookInfo = $cache->data;
+      }
+      else {
+        $this->hookInfo = parent::getHookInfo();
+        $this->bootstrapCache->set('hook_info', $this->hookInfo);
+      }
+    }
+    return $this->hookInfo;
+  }
+
+  /**
+   * Implements \Drupal\Core\Extension\ModuleHandlerInterface::resetImplementations().
+   */
+  public function resetImplementations() {
+    // We maintain a persistent cache of hook implementations in addition to the
+    // static cache to avoid looping through every module and every hook on each
+    // request. Benchmarks show that the benefit of this caching outweighs the
+    // additional database hit even when using the default database caching
+    // backend and only a small number of modules are enabled. The cost of the
+    // $this->bootstrapCache->get() is more or less constant and reduced further when
+    // non-database caching backends are used, so there will be more significant
+    // gains when a large number of modules are installed or hooks invoked, since
+    // this can quickly lead to \Drupal::moduleHandler()->implementsHook() being
+    // called several thousand times per request.
+    parent::resetImplementations();
+    $this->bootstrapCache->set('module_implements', array());
+    $this->bootstrapCache->delete('hook_info');
+  }
+
+  /**
+   * Implements \Drupal\Core\Extension\CachedModuleHandlerInterface::writeCache().
+   */
+  public function writeCache() {
+    if ($this->cacheNeedsWriting) {
+      $this->bootstrapCache->set('module_implements', $this->implementations);
+      $this->cacheNeedsWriting = FALSE;
+    }
+  }
+
+  /**
+   * Overrides \Drupal\Core\Extension\ModuleHandler::getImplementationInfo().
+   */
+  protected function getImplementationInfo($hook) {
+    if (!isset($this->implementations)) {
+      $this->implementations = $this->getCachedImplementationInfo();
+    }
+    if (!isset($this->implementations[$hook])) {
+      // The hook is not cached, so ensure that whether or not it has
+      // implementations, the cache is updated at the end of the request.
+      $this->cacheNeedsWriting = TRUE;
+      $this->implementations[$hook] = parent::getImplementationInfo($hook);
+    }
+    else {
+      foreach ($this->implementations[$hook] as $module => $group) {
+        // If this hook implementation is stored in a lazy-loaded file, include
+        // that file first.
+        if ($group) {
+          $this->loadInclude($module, 'inc', "$module.$group");
+        }
+        // It is possible that a module removed a hook implementation without the
+        // implementations cache being rebuilt yet, so we check whether the
+        // function exists on each request to avoid undefined function errors.
+        // Since \Drupal::moduleHandler()->implementsHook() may needlessly try to
+        // load the include file again, function_exists() is used directly here.
+        if (!function_exists($module . '_' . $hook)) {
+          // Clear out the stale implementation from the cache and force a cache
+          // refresh to forget about no longer existing hook implementations.
+          unset($this->implementations[$hook][$module]);
+          $this->cacheNeedsWriting = TRUE;
+        }
+      }
+    }
+    return $this->implementations[$hook];
+  }
+
+  /**
+   * Retrieves hook implementation info from the cache.
+   */
+  protected function getCachedImplementationInfo() {
+    if ($cache = $this->bootstrapCache->get('module_implements')) {
+      return $cache->data;
+    }
+    else {
+      return array();
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Extension/ExtensionEvent.php b/core/lib/Drupal/Core/Extension/ExtensionEvent.php
new file mode 100644
index 0000000..401f6d9
--- /dev/null
+++ b/core/lib/Drupal/Core/Extension/ExtensionEvent.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Extension\ExtensionEvent.
+ */
+
+namespace Drupal\Core\Extension;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Event object for extension events.
+ */
+class ExtensionEvent extends Event {
+
+  /**
+   * The name of the extension.
+   *
+   * @var string
+   */
+  protected $extension;
+
+  /**
+   * @param string $module
+   */
+  public function __construct($extension) {
+    $this->extension = $extension;
+  }
+
+  /**
+   * Returns the name of the extension this event has been invoked for.
+   *
+   * @return string
+   *   The module name.
+   */
+  public function getExtension() {
+    return $this->extension;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Extension/ExtensionsEvent.php b/core/lib/Drupal/Core/Extension/ExtensionsEvent.php
new file mode 100644
index 0000000..059aa33
--- /dev/null
+++ b/core/lib/Drupal/Core/Extension/ExtensionsEvent.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Extension\ExtensionsEvent.
+ */
+
+namespace Drupal\Core\Extension;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Event object for events containing multiple extensions.
+ */
+class ExtensionsEvent extends Event {
+
+  /**
+   * An array of extensions.
+   *
+   * @var array
+   */
+  protected $extensions;
+
+  /**
+   * @param string $module
+   */
+  public function __construct(array $extensions) {
+    $this->extensions = $extensions;
+  }
+
+  /**
+   * Returns a list of extensions this event has been invoked for.
+   *
+   * @return array
+   *   A list of extensions.
+   */
+  public function getExtensions() {
+    return $this->extensions;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Extension/ModuleEvents.php b/core/lib/Drupal/Core/Extension/ModuleEvents.php
new file mode 100644
index 0000000..c35fc97
--- /dev/null
+++ b/core/lib/Drupal/Core/Extension/ModuleEvents.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Extension\ModuleEvents.
+ */
+
+namespace Drupal\Core\Extension;
+
+/**
+ * Defines module events.
+ */
+final class ModuleEvents {
+
+  /**
+   * Fired before a module is installed.
+   *
+   * @see \Drupal\Core\Extension\ModuleHandler::install()
+   */
+  const PREINSTALL = 'module.preinstall';
+
+  /**
+   * Fired when a module is installed.
+   *
+   * @see \Drupal\Core\Extension\ModuleHandler::install()
+   */
+  const INSTALL = 'module.install';
+
+  /**
+   * Fired after modules have been installed.
+   *
+   * @see \Drupal\Core\Extension\ModuleHandler::install()
+   */
+  const INSTALLED = 'module.installed';
+
+  /**
+   * Fired before a module is uninstalled.
+   *
+   * @see \Drupal\Core\Extension\ModuleHandler::uninstall()
+   */
+  const PREUNINSTALL = 'module.preuninstall';
+
+  /**
+   * Fired when a module is uninstalled.
+   *
+   * @see \Drupal\Core\Extension\ModuleHandler::uninstall()
+   */
+  const UNINSTALL = 'module.uninstall';
+
+  /**
+   * Fired after modules have been uninstalled.
+   *
+   * @see \Drupal\Core\Extension\ModuleHandler::uninstall()
+   */
+  const UNINSTALLED = 'module.installed';
+
+}
diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php
index 08a3ec5..2ab6bc4 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php
@@ -9,8 +9,10 @@
 
 use Drupal\Component\Graph\Graph;
 use Drupal\Component\Serialization\Yaml;
-use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleEvents;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Drupal\Component\Utility\NestedArray;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -77,6 +79,13 @@ class ModuleHandler implements ModuleHandlerInterface {
   protected $alterFunctions;
 
   /**
+   * The event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
    * Constructs a ModuleHandler object.
    *
    * @param array $module_list
@@ -85,12 +94,16 @@ class ModuleHandler implements ModuleHandlerInterface {
    *   %container.modules% parameter being set up by DrupalKernel.
    * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
    *   Cache backend for storing module hook implementation information.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    *
    * @see \Drupal\Core\DrupalKernel
    * @see \Drupal\Core\CoreServiceProvider
    */
-  public function __construct(array $module_list = array(), CacheBackendInterface $cache_backend) {
+  public function __construct(array $module_list = array(), CacheBackendInterface $cache_backend, EventDispatcherInterface $event_dispatcher) {
     $this->moduleList = array();
+    $this->eventDispatcher = $event_dispatcher;
+
     foreach ($module_list as $name => $module) {
       $this->moduleList[$name] = new Extension($module['type'], $module['pathname'], $module['filename']);
     }
@@ -761,13 +774,12 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
 
         // Allow modules to react prior to the installation of a module.
         $this->invokeAll('module_preinstall', array($module));
+        $module_event = new ExtensionEvent($module);
+        $this->eventDispatcher->dispatch(ModuleEvents::PREINSTALL, $module_event);
 
         // Now install the module's schema if necessary.
         drupal_install_schema($module);
 
-        // Clear plugin manager caches.
-        \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();
-
         // Set the schema version to the number of the last update provided by
         // the module, or the minimum core schema version.
         $version = \Drupal::CORE_MINIMUM_SCHEMA_VERSION;
@@ -813,7 +825,8 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
 
         // Allow the module to perform install tasks.
         $this->invoke($module, 'install');
-
+        $module_event = new ExtensionEvent($module);
+        $this->eventDispatcher->dispatch(ModuleEvents::INSTALL, $module_event);
         // Record the fact that it was installed.
         watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO);
       }
@@ -822,6 +835,9 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
     // If any modules were newly installed, invoke hook_modules_installed().
     if (!empty($modules_installed)) {
       $this->invokeAll('modules_installed', array($modules_installed));
+      $modules_event = new ExtensionsEvent($modules_installed);
+      $this->eventDispatcher->dispatch(ModuleEvents::INSTALLED, $modules_event);
+
     }
 
     return TRUE;
@@ -883,6 +899,8 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
     foreach ($module_list as $module) {
       // Allow modules to react prior to the uninstallation of a module.
       $this->invokeAll('module_preuninstall', array($module));
+      $module_event = new ExtensionEvent($module);
+      $this->eventDispatcher->dispatch(ModuleEvents::PREUNINSTALL, $module_event);
 
       // Uninstall the module.
       module_load_install($module);
@@ -904,15 +922,13 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       unset($module_filenames[$module]);
       $this->setModuleList($module_filenames);
 
-      // Remove any potential cache bins provided by the module.
-      $this->removeCacheBins($module);
-
       // Clear the static cache of system_rebuild_module_data() to pick up the
       // new module, since it merges the installation status of modules into
       // its statically cached list.
       drupal_static_reset('system_rebuild_module_data');
 
-      \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();
+      $module_event = new ExtensionEvent($module);
+      $this->eventDispatcher->dispatch(ModuleEvents::UNINSTALL, $module_event);
 
       // Update the kernel to exclude the uninstalled modules.
       \Drupal::service('kernel')->updateModules($module_filenames, $module_filenames);
@@ -929,14 +945,13 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO);
 
       $schema_store->delete($module);
-
-      // Make sure any route data is also removed for this module.
-      \Drupal::service('router.dumper')->dump(array('provider' => $module));
     }
     drupal_get_installed_schema_version(NULL, TRUE);
 
     // Let other modules react.
     $this->invokeAll('modules_uninstalled', array($module_list));
+    $modules_event = new ExtensionsEvent($module_list);
+    $this->eventDispatcher->dispatch(ModuleEvents::UNINSTALLED, $modules_event);
 
     drupal_flush_all_caches();
 
@@ -944,45 +959,6 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
   }
 
   /**
-   * Helper method for removing all cache bins registered by a given module.
-   *
-   * @param string $module
-   *   The name of the module for which to remove all registered cache bins.
-   */
-  protected function removeCacheBins($module) {
-    // Remove any cache bins defined by a module.
-    $service_yaml_file = drupal_get_path('module', $module) . "/$module.services.yml";
-    if (file_exists($service_yaml_file)) {
-      $definitions = Yaml::decode(file_get_contents($service_yaml_file));
-      if (isset($definitions['services'])) {
-        foreach ($definitions['services'] as $id => $definition) {
-          if (isset($definition['tags'])) {
-            foreach ($definition['tags'] as $tag) {
-              // This works for the default cache registration and even in some
-              // cases when a non-default "super" factory is used. That should
-              // be extremely rare.
-              if ($tag['name'] == 'cache.bin' && isset($definition['factory_service']) && isset($definition['factory_method']) && !empty($definition['arguments'])) {
-                try {
-                  $factory = \Drupal::service($definition['factory_service']);
-                  if (method_exists($factory, $definition['factory_method'])) {
-                    $backend = call_user_func_array(array($factory, $definition['factory_method']), $definition['arguments']);
-                    if ($backend instanceof CacheBackendInterface) {
-                      $backend->removeBin();
-                    }
-                  }
-                }
-                catch (\Exception $e) {
-                  watchdog_exception('system', $e, 'Failed to remove cache bin defined by the service %id.', array('%id' => $id));
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function getModuleDirectories() {
diff --git a/core/lib/Drupal/Core/Plugin/CachedDiscoveryClearer.php b/core/lib/Drupal/Core/Plugin/CachedDiscoveryClearer.php
index 5febcd3..c9459a8 100644
--- a/core/lib/Drupal/Core/Plugin/CachedDiscoveryClearer.php
+++ b/core/lib/Drupal/Core/Plugin/CachedDiscoveryClearer.php
@@ -8,13 +8,14 @@
 namespace Drupal\Core\Plugin;
 
 use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
-use Drupal\Component\Plugin\Exception\PluginException;
-use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Core\Extension\ModuleEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
 
 /**
  * Defines a class which is capable of clearing the cache on plugin managers.
  */
-class CachedDiscoveryClearer {
+class CachedDiscoveryClearer implements EventSubscriberInterface {
 
   /**
    * The stored discoveries.
@@ -43,4 +44,14 @@ public function clearCachedDefinitions() {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  static function getSubscribedEvents() {
+    $events[ModuleEvents::PREINSTALL][] = array('clearCachedDefinitions');
+    $events[ModuleEvents::UNINSTALL][] = array('clearCachedDefinitions');
+
+    return $events;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Routing/MatcherDumper.php b/core/lib/Drupal/Core/Routing/MatcherDumper.php
index b5e1338..3b0273a 100644
--- a/core/lib/Drupal/Core/Routing/MatcherDumper.php
+++ b/core/lib/Drupal/Core/Routing/MatcherDumper.php
@@ -7,7 +7,10 @@
 
 namespace Drupal\Core\Routing;
 
+use Drupal\Core\Extension\ExtensionsEvent;
+use Drupal\Core\Extension\ModuleEvents;
 use Drupal\Core\State\StateInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Symfony\Component\Routing\RouteCollection;
 
 use Drupal\Core\Database\Connection;
@@ -15,7 +18,7 @@
 /**
  * Dumps Route information to a database table.
  */
-class MatcherDumper implements MatcherDumperInterface {
+class MatcherDumper implements MatcherDumperInterface, EventSubscriberInterface {
 
   /**
    * The database connection to which to dump route information.
@@ -175,4 +178,25 @@ public function getRoutes() {
     return $this->routes;
   }
 
+  /**
+   * Event listener when modules are uninstalled.
+   *
+   * @param \Drupal\Core\Extension\ExtensionsEvent $event
+   *   The event.
+   */
+  public function onModulesUninstall(ExtensionsEvent $event) {
+    // Make sure any route data is also removed for uninstalled modules.
+    foreach ($event->getExtensions() as $module) {
+      $this->dump(array('provider' => $module));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  static function getSubscribedEvents() {
+    $events[ModuleEvents::UNINSTALLED][] = array('onModulesUninstall');
+    return $events;
+  }
+
 }
