Spring @ConditionalOnBean in combination with @Component

Viewed 1519

Having the next situation:


@ConditionalOnBean(ServiceD.class)
@Component
class ServiceAImpl implements ServiceA {

    private ServiceB serviceB;
    private ServiceC serviceC;
    private ServiceD serviceD;

    public ServiceA(ServiceB serviceB, ServiceC serviceC, ServiceD serviceD) {
        this.serviceB = serviceB;
        this.serviceC = serviceC;
        this.serviceD = serviceD;
    }
}

interface ServiceD {

    void doStuff();
}

@Component
class ServiceDImpl implements ServiceD {

    private ServiceE serviceE;

    public ServiceD(ServiceE serviceE) {
        this.serviceE = serviceE;
    }

    @Override
    public void doStuff() {
        //...
    }
}

I need serviceA to be loaded only if there exists a serviceD implementation.

From @ConditionalOnBean documentation: "The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only.".

My question is: As ServiceD is a dependency of ServiceA, will this guarantee that when @ConditionalOnBean is evaluated, ServiceD will be already processed by the application context?

If not, is there any other way to acomplished that without using autoconfiguration classes?

2 Answers

This is a known issue. There is no guarantee that ServiceD bean would be created before ServiceA, as you cannot change the order of bean registration from @ComponentScan. It's why the documentation says to use the condition on auto-configuration classes only. So you either have to make ServiceA auto-configured, so that all your other defined beans are defined before ServiceA bean, or use a different annotation such as @ConditionalOnClass.

By default Spring manages beans' lifecycle and arranges their initialization order.

But, we can still customize it based on our needs. We can choose either the SmartLifeCycle interface or the @DependsOn annotation for managing initialization order.

You can try @DependsOn By using this annotation for specifying bean dependencies. Spring guarantees that the defined beans will be initialized before attempting an initialization of the current bean. Please refer the documentation

Related