DEV Community

Cover image for How to programmatically look up a bean in Quarkus
Ivelin Yanev
Ivelin Yanev

Posted on

2 1

How to programmatically look up a bean in Quarkus

In Quarkus, a modern Java framework optimized for cloud-native and serverless applications, Contexts and Dependency Injection (CDI) is a core feature for managing beans. While dependency injection via @Inject is the standard way to access beans, there are scenarios where you need to programmatically look up beans at runtime. This article explores various methods to programmatically look up beans in Quarkus, with practical examples and best practices.

Why would you need programmatic bean lookup?

  • You need to resolve beans dynamically based on runtime conditions (e.g., selecting a specific implementation).

  • You’re working in a non-CDI-managed class (e.g., a static context, utility class or third-party integrations).

  • You need to iterate over all beans of a given type or select beans with specific qualifiers.

  • You want to check for bean availability or defer bean resolution for performance reasons.

Quarkus provides several approaches to programmatically look up beans, leveraging its optimized CDI implementation, Arc. The primary methods include using the Arc container, the standard CDI API, Instance<T> with or without @Any.

Methods for programmatic bean lookup

For all examples, we'll use the following bean interface and implementation:

public interface MyBean {
  String getName();
  void doSomething();
}

@ApplicationScoped
public class BeanImpl1 implements MyBean{

  @Override
  public String getName() {
    return "Standard Bean";
  }

  @Override
  public void doSomething() {
    System.out.println("BeanImpl1 is working!");
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Using the Arc Container(Quarkus-specific)

The Arc container is Quarkus CDI implementation, optimized for fast startup and low memory usage. It provides a straightforward API for programmatic bean lookup via Arc.container().

 InstanceHandle<MyBean> beanHandle = Arc.container().instance(MyBean.class);
    if (beanHandle.isAvailable()) {
      MyBean myBean = beanHandle.get();
      myBean.doSomething();
    } else {
      System.out.println("MyBean not found");
    }
Enter fullscreen mode Exit fullscreen mode

However, when running this code, you might encounter the following error:

================================================================================
CDI: programmatic lookup problem detected
-----------------------------------------
At least one bean matched the required type and qualifiers but was marked as unused and removed during build

Stack frame: 
Required type: interface org.acme.beans.MyBean
Required qualifiers: [@jakarta.enterprise.inject.Default()]
Removed beans:
        - CLASS bean  [types=[interface org.acme.beans.MyBean, class org.acme.beans.BeanImpl1], qualifiers=null]
Solutions:
        - Application developers can eliminate false positives via the @Unremovable annotation
        - Extensions can eliminate false positives via build items, e.g. using the UnremovableBeanBuildItem
        - See also https://quarkus.io/guides/cdi-reference#remove_unused_beans
        - Enable the DEBUG log level to see the full stack trace
================================================================================
Enter fullscreen mode Exit fullscreen mode

Understanding the Problem

Quarkus uses build-time optimization to improve startup time and reduce memory usage. Part of this optimization is unused bean removal, where Quarkus analyzes your application at build time and removes beans that appear to be unused.

When using Arc.container().instance(MyBean.class) for programmatic lookup, you're encountering this error because Quarkus couldn't detect at build time that BeanImpl1 (which implements MyBean) would be needed at runtime. The bean was considered "unused" and was removed during the build process, and when you try to look it up at runtime, it's no longer available.

Solutions to Fix the Problem

1.Mark Your Bean as @Unremovable

@Unremovable
@ApplicationScoped
public class BeanImpl1 implements MyBean {
    // Implementation
}
Enter fullscreen mode Exit fullscreen mode

2.Disable Unused Bean Removal (in application.properties)

quarkus.arc.remove-unused-beans=false

  • Using the Standard CDI API
    MyBean myBean = CDI.current().select(MyBean.class).get();
    myBean.doSomething();
Enter fullscreen mode Exit fullscreen mode
  • Using @Inject with Instance<T>

For CDI-managed beans, using Instance<T> offers a flexible approach to dynamic lookup.

  @Inject
  Instance<MyBean> myBeanInstance;

  if (myBeanInstance.isResolvable()) {
      MyBean bean = myBeanInstance.get();
      bean.doSomething();
    }
Enter fullscreen mode Exit fullscreen mode
  • Using @Any with Instance<T>

The @Any qualifier extends Instance<T> capabilities to access all beans of a type regardless of qualifiers, which is particularly useful for plugins or strategy patterns.

Let's create an additional implementation for our bean:

@ApplicationScoped
public class BeanImpl2 implements MyBean{

  @Override
  public String getName() {
    return "Specific BeanImpl2";
  }

  @Override
  public void doSomething() {
    System.out.println("BeanImpl2 (specificBean) is working!");
  }
}
Enter fullscreen mode Exit fullscreen mode

Now we can look up all beans:

  @Inject
  @Any
  Instance<MyBean> allBeans;

  System.out.println("Found " + allBeans.stream().count() + "implementations");

  allBeans.forEach(bean -> {
    System.out.println("Processing bean: " + bean.getClass().getSimpleName());
      bean.doSomething();
    });
Enter fullscreen mode Exit fullscreen mode

Output:

Found 2 implementations
Processing bean: BeanImpl1_ClientProxy
BeanImpl1 is working!
Processing bean: BeanImpl2_ClientProxy
BeanImpl2 (specificBean) is working!
Enter fullscreen mode Exit fullscreen mode

Conclusion

Programmatic bean lookup in Quarkus provides flexibility for dynamic bean resolution and working with multiple implementations. While @Inject should remain your primary approach for accessing beans in most scenarios, the methods described in this article offer powerful alternatives for specific use cases.

When choosing a lookup method, consider:

  • Build-time optimization impacts (remember the @Unremovable annotation when needed)
  • Whether you need to access multiple beans or specific implementations
  • The context in which you're performing the lookup (CDI-managed vs. non-CDI-managed.

Short-term memory for faster AI agents

Short-term memory for faster AI agents

AI agents struggle with latency and context switching. Redis fixes it with a fast, in-memory layer for short-term context—plus native support for vectors and semi-structured data to keep real-time workflows on track.

Start building

Top comments (0)

Java-ready auth and billing that just works

Java-ready auth and billing that just works

Stop building auth from scratch. Kinde handles authentication, user management, and billing so you can focus on what matters - shipping great products your users will love.

Get a free account

Announcing the First DEV Education Track: "Build Apps with Google AI Studio"

The moment is here! We recently announced DEV Education Tracks, our new initiative to bring you structured learning paths directly from industry experts.

Dive in and Learn

DEV is bringing Education Tracks to the community. Dismiss if you're not interested. ❤️