Search code examples
jakarta-eesynchronizationcdiweld

Is beanManager.getReference() thread-safe?


I have class that is marked with @Singleton.

To get instance of that class I use the following code:

public Object getMySingleton(Class someClass){
   Bean bean = (Bean) beanManager.getBeans(someClass).iterator().next();
   CreationalContext ctx = beanManager.createCreationalContext(bean);
   Object obj =beanManager.getReference(bean, someClass, ctx);
   return obj;
}

Please, pay attention that getMySingleton is not synchronized. Is this code thread-safe? I mean, that getMySingleton can be called from different threads - will I get in all callers the same instance of Singleton?

As javaee server I use glassfish and weld as cdi container. However, I would like to get common answer according to java-ee specs.


Solution

  • Yes, it is.

    The getReference() actually returns a proxy instance which in turn delegates to the actual instance. It roughly looks like this for a fictive SomeBean class:

    public SomeBeanCDIProxy extends SomeBean implements Serializable {
    
        public String getSomeProperty() {
            SomeBean instance = CDI.resolveItSomehow();
            return instance.getSomeProperty();
        }
    
        public void setSomeProperty(String someProperty) {
            SomeBean instance = CDI.resolveItSomehow();
            instance.setSomeProperty(someProperty);
        }
    
    }
    

    The actual instance is not necessarily created and available at the moment the proxy instance is created and returned. Only when you call one of the bean methods on the proxy, and the actual instance isn't available in its scope, then CDI will create the actual instance and delegate the method call to it. Regardless of the way how you obtain the proxy (manual or injection), the actual instance is logically being created in a thread safe manner. Otherwise it would also not have worked for injection.