Skip to content

A service is a plugin component loaded on demand when your plugin first requests it.

The Consulo ensures that only one instance of a service is loaded even though it is called several times. Services are registered via annotations (@ServiceAPI and @ServiceImpl) rather than XML.

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.

To obtain a service instance, use Application.get().getInstance(MyService.class) for application-level services, or project.getInstance(MyService.class) for project-level services. You can also use constructor injection with @Inject.

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

Types

The Consulo 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.

INFO

Please consider not using module-level services because it can increase memory usage for projects with many modules.

Constructor

Consulo uses @Inject for constructor injection in services. Project/Module level service constructors can receive a Project/Module argument via @Inject. To improve startup performance, avoid any heavy initializations in the constructor.

INFO

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

Declaring a Service

Services are declared using the @ServiceAPI and @ServiceImpl annotations.

@ServiceAPI is placed on the service interface (or class, if there is no separate interface) and requires a ComponentScope parameter to specify the service level:

  • ComponentScope.APPLICATION - application level service
  • ComponentScope.PROJECT - project level service
  • ComponentScope.MODULE - module level service (not recommended, see Note above)

@ServiceImpl is placed on the implementation class.

Application-Level Service Example

java
@ServiceAPI(ComponentScope.APPLICATION)
public interface MyService {
    static MyService getInstance() {
        return Application.get().getInstance(MyService.class);
    }

    void doSomething();
}

@ServiceImpl
public class MyServiceImpl implements MyService {
    @Override
    public void doSomething() { /* ... */ }
}

Project-Level Service Example

java
@ServiceAPI(ComponentScope.PROJECT)
public interface MyProjectService {
    void doSomething();
}

@ServiceImpl
public class MyProjectServiceImpl implements MyProjectService {
    private final Project myProject;

    @Inject
    public MyProjectServiceImpl(Project project) {
        myProject = project;
    }

    @Override
    public void doSomething() { /* ... */ }
}

Retrieving a Service

Getting a service does not 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 the service is fully initialized.

For application-level services:

java
MyService service = Application.get().getInstance(MyService.class);

For project-level services:

java
MyProjectService service = project.getInstance(MyProjectService.class);

You can also define a static convenience method on the service interface itself (as shown in the application-level example above).

Project Service Sample

This sample shows a ProjectService interacting with another project level service AnotherService (not shown here).

ProjectService.java

java
@ServiceAPI(ComponentScope.PROJECT)
public interface ProjectService {

    void someServiceMethod(String parameter);
}

ProjectServiceImpl.java

java
@ServiceImpl
public class ProjectServiceImpl implements ProjectService {

    private final Project myProject;

    @Inject
    public ProjectServiceImpl(Project project) {
        myProject = project;
    }

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