7.1 KiB

Services

Registering and using on-demand services to encapsulate plugin functionality.

A service is a plugin component loaded on demand when your plugin calls the getService() method of corresponding ComponentManager instance (see Types). The IntelliJ Platform ensures that only one instance of a service is loaded even though it is called several times. Services are used to encapsulate logic operating on a set of related classes or to provide some reusable functionality that can be used across the plugin project, and conceptually don't differ from the service classes in other languages or frameworks.

A service must have an implementation class that is used for service instantiation. A service may also have an interface class used to obtain the service instance and provide the service's API.

A service needing a shutdown hook/cleanup routine can implement Disposable and perform necessary work in dispose() (see Automatically Disposed Objects).

Types

The IntelliJ Platform offers three types of services: application-level services (global singleton), project-level services, and module-level services. For the latter two, a separate instance of the service is created for each instance of its corresponding scope, see Project Model Introduction.

Avoid using module-level services as it can increase memory usage for projects with many modules.

{style="note"}

Constructor

Project/Module-level service constructors can have a Project/Module argument. To improve startup performance, avoid any heavy initializations in the constructor.

Using constructor injection of dependency services is deprecated (and not supported in ) for performance reasons.

Other dependencies must be acquired only when needed in all corresponding methods (see someServiceMethod() in Project Service Sample).

Use inspection Plugin DevKit | Code | Non-default constructors for service and extension class to verify code.

{style="warning"}

Light Services

A service not going to be overridden does not need to be registered in plugin.xml (see Declaring a Service). Instead, annotate service class with @Service. Project-level services must specify @Service(Service.Level.PROJECT). The service instance will be created in scope according to the caller (see Retrieving a Service).

Restrictions:

  • Service class must be final.
  • Constructor injection of dependency services is not supported.
  • If application-level service is a PersistentStateComponent, roaming must be disabled (roamingType = RoamingType.DISABLED).

See Project-Level Service below for a sample.

Declaring a Service

To register a non-Light Service, distinct extension points are provided for each type:

  • com.intellij.applicationService - application-level service
  • com.intellij.projectService - project-level service
  • com.intellij.moduleService - module-level service (not recommended, see Note above)

To expose service API, create separate class for serviceInterface and extend it in corresponding class registered in serviceImplementation. If serviceInterface isn't specified, it's supposed to have the same value as serviceImplementation.

To provide custom implementation for test/headless environment, specify testServiceImplementation/headlessImplementation additionally.

plugin.xml

<extensions defaultExtensionNs="com.intellij">
  <!-- Declare the application-level service -->
  <applicationService
      serviceInterface="mypackage.MyApplicationService"
      serviceImplementation="mypackage.MyApplicationServiceImpl"/>

  <!-- Declare the project-level service -->
  <projectService
      serviceInterface="mypackage.MyProjectService"
      serviceImplementation="mypackage.MyProjectServiceImpl"/>
</extensions>

If declared services are intended to be used by other plugins depending on your plugin, consider bundling their sources in the plugin distribution.

{style="note"}

Retrieving a Service

Do not acquire service instances eagerly or store them in fields, but obtain them in the place(s) where they will be used.

{style="warning"}

Getting service doesn't need a read action and can be performed from any thread. If a service is requested from several threads, it will be initialized in the first thread, and other threads will be blocked until it is fully initialized.

MyApplicationService applicationService = ApplicationManager.getApplication()
  .getService(MyApplicationService.class);

MyProjectService projectService = project.getService(MyProjectService.class);

Service implementations can wrap these calls with convenient static getInstance() or getInstance(Project) method:

MyApplicationService applicationService = MyApplicationService.getInstance();

MyProjectService projectService = MyProjectService.getInstance(project);
val applicationService = service<MyApplicationService>()

val projectService = project.service<MyProjectService>()

Getting Service{thumbnail="true" thumbnail-same-file="true"}

Project Service Sample

This minimal sample shows Light Service ProjectService interacting with another project-level service AnotherService (not shown here).

ProjectService.java

@Service(Service.Level.PROJECT)
public final class ProjectService {

  private final Project myProject;

  public ProjectService(Project project) {
    myProject = project;
  }

  public void someServiceMethod(String parameter) {
    AnotherService anotherService = myProject.getService(AnotherService.class);
    String result = anotherService.anotherServiceMethod(parameter, false);
    // do some more stuff
  }
}

Sample Plugin

To clarify how to use services, consider the maxOpenProjects sample plugin available in the code samples.

This plugin has an application service counting the number of currently opened projects in the IDE. If this number exceeds the maximum number of simultaneously opened projects allowed by the plugin (3), it displays a warning message.

See Code Samples on how to set up and run the plugin.