> Markdown version of [Vaadin Service Interfaces as CDI Beans](https://vaadin.com/docs/next/flow/integrations/cdi/service-beans). Section index: [llms.txt](https://vaadin.com/docs/next/flow/llms.txt)

# Vaadin Service Interfaces as CDI Beans

Some Vaadin service interfaces can be implemented as CDI beans. If you do this, the service interface becomes a managed bean with CDI features. In which case, there is no need to register the implementation in Vaadin.

The [Vaadin CDI](https://vaadin.com/directory/component/vaadin-cdi/) add-on references the following interfaces:

- `I18NProvider`

- `InstantiatorFactory`

- `SystemMessagesProvider`

- `ErrorHandler`

- `Executor`

To ensure the beans are recognized, they should be qualified by the `@VaadinServiceEnabled` annotation. This is required because it marks a bean which is used as an `I18NProvider` by the service. If there are any other `I18NProvider` beans, the one that’s also used by the service is used.

An example of this is using the `@VaadinServiceEnabled` annotation to qualify `TestSystemMessagesProvider`.

```java
@VaadinServiceEnabled
@VaadinServiceScoped
public class TestSystemMessagesProvider
        implements SystemMessagesProvider {

    @Override
    public SystemMessages getSystemMessages(
            SystemMessagesInfo systemMessagesInfo) {
        CustomizedSystemMessages messages =
                new CustomizedSystemMessages();
        messages.setInternalErrorMessage(
                "Sorry, something went wrong :(");
        return messages;
    }
}

@Route
 public class SampleView extends Div {

     @VaadinServiceEnabled
     @Inject
     private TestSystemMessagesProvider messageProvider;

 }
```

The purpose of `@VaadinServiceScoped` is to define a context of the lifespan of the Vaadin service. It isn’t necessary for this kind of bean, but it’s recommended because other Vaadin contexts can be problematic.

For example, there’s no guarantee that an active Vaadin session or UI context exists when the add-on looks for any of these beans. It’s safe, though, to use standard CDI `@Dependent` and `@ApplicationScoped` contexts.

## <a id="configure-custom-vaadin-executor"></a>Configure Custom Vaadin Executor

When a Vaadin application starts in a CDI environment, the `CdiVaadinServletService` overrides the `createDefaultExecutor()` method to use CDI capabilities for selecting an appropriate `Executor` for executing Vaadin’s internal tasks. The selection process follows this order:

1. Look for a custom `Executor` bean qualified with the `@VaadinServiceEnabled` annotation

2. If no custom executor is found, try to use the container’s `ManagedExecutorService` (available in Jakarta EE environments)

3. If neither is available, fall back to Vaadin’s [default executor](https://vaadin.com/docs/next/flow/advanced/service-executor.md) implementation

To avoid ambiguity, the CDI extension enforces these rules:

- There can be at most one `Executor` bean annotated with `@VaadinServiceEnabled`

- If multiple `Executor` beans with `@VaadinServiceEnabled` annotation are found, the application deployment will fail with an appropriate error message

You can provide your own task executor to customize how Vaadin executes server-side operations. This can be useful for implementing custom threading models, using specific thread pools, or integrating with other execution frameworks. To provide a custom executor, define a CDI bean that implements the `Executor` interface and annotate it with `@VaadinServiceEnabled`:

```java
@ApplicationScoped
public class ExecutorConfiguration {

    @Produces
    @Singleton
    @VaadinServiceEnabled
    public Executor vaadinTaskExecutor() {
        ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
            16, // Core pool size
            32, // Maximum pool size
            120, // Keep-alive time
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(),
            r -> {
                Thread thread = new Thread(r, "CustomVaadinExecutor-" + r.hashCode());
                thread.setDaemon(true);
                return thread;
            });
        customExecutor.allowCoreThreadTimeOut(true);
        return customExecutor;
    }
}
```

`A55D3416-D5B7-40B9-8C4A-1454E97C92F1`
