Close

Spring - Required dependency checking

[Last Updated: Jun 11, 2021]

For a large project where many developers work in parallel, it's desirable to have some framework level facilities to check that all mandatory dependencies have been set or not. This check should ideally be performed at compile time, if not possible then as early as start up time, before we start having NullPointerException on missing values. Spring offers various dependency checking mechanism during start up time.

Let's explore some aspects and options provided by Spring framework regarding dependency checking.


Constructor vs setter injection

As we discussed in the tutorial, different ways to do dependency injection, we should always use constructors based injection for the mandatory properties (with programmatic validation of arguments) and setter based injection for optional properties.

There might still be many reasons we want to use setters for mandatory properties rather than constructor. May be our constructor is getting too complex, may be we want to reconfigure some properties later (of course they cannot be final in that case but still are mandatory at wiring time).

Dependency injection via constructors

Spring throws UnsatisfiedDependencyException if the required dependency is missing for the target constructor

package com.logicbig.example;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Configuration
@ComponentScan(useDefaultFilters = false,
        includeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "ConstructorDiExample"))
public class ConstructorDiExample {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(ConstructorDiExample.class);
        ClientBean bean = context.getBean(ClientBean.class);
        bean.doSomething();
    }

    @Component
    private static class ClientBean {
        private final ServiceBean serviceBean;

        private ClientBean(ServiceBean serviceBean) {
            this.serviceBean = serviceBean;
        }

        void doSomething() {
            System.out.println("doing something with: " + serviceBean);
        }
    }

    //uncomment @service to get rid of UnsatisfiedDependencyException
   // @Service
    private class ServiceBean {

    }
}

Output

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.logicbig.example.ConstructorDiExample$ClientBean': Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type [com.logicbig.example.ConstructorDiExample$ServiceBean] found for dependency [com.logicbig.example.ConstructorDiExample$ServiceBean]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.logicbig.example.ConstructorDiExample$ServiceBean] found for dependency [com.logicbig.example.ConstructorDiExample$ServiceBean]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}


How to check required properties in setter injection?

If we are doing setter injection for required dependencies then we have following options for dependency checking:


Setter injection with @Autowire

If we are using default method of autowiring i.e. Autowire.NO then we need to explicitly use @Autowire at injection point (except for constructor since Spring 4.3). The annotation @Autowire#required attribute is true by default. So Spring throws UnsatisfiedDependencyException if the dependency via setter is not provided.

package com.logicbig.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Configuration
@ComponentScan(useDefaultFilters = false,
        includeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "SetterAutowiredExample"))
public class SetterAutowiredExample {

    public static void main(String... strings) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                SetterAutowiredExample.class);
        ClientBean bean = context.getBean(ClientBean.class);
        bean.doSomething();
    }

    @Component
    public static class ClientBean {
        private ServiceBean serviceBean;

        @Autowired
        public void setServiceBean(ServiceBean serviceBean) {
            this.serviceBean = serviceBean;
        }

        public void doSomething() {
            System.out.println("doing something with : " + serviceBean);
        }
    }

    //uncomment following to  get rid of UnsatisfiedDependencyException
    //@Service
    public static class ServiceBean {
    }
}

Output

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.logicbig.example.SetterAutowiredExample$ClientBean': Unsatisfied dependency expressed through method 'setServiceBean' parameter 0: No qualifying bean of type [com.logicbig.example.SetterAutowiredExample$ServiceBean] found for dependency [com.logicbig.example.SetterAutowiredExample$ServiceBean]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.logicbig.example.SetterAutowiredExample$ServiceBean] found for dependency [com.logicbig.example.SetterAutowiredExample$ServiceBean]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}

Setter injection without @Autowire but with @PostConstruct validation

Using default autowiring mode Autowiring.NO:

package com.logicbig.example;


import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;

@Configuration
public class PostConstructExample {

    @Bean
    public ClientBean clientBean (ServiceBean serviceBean) {
        ClientBean clientBean = new ClientBean();
        //uncomment following to get rid of IllegalArgumentException
        //clientBean.setServiceBean(serviceBean);
        return clientBean;
    }

    @Bean
    public ServiceBean serviceBean () {
        return new ServiceBean();
    }

    public static void main (String... strings) {
        AnnotationConfigApplicationContext context =
                            new AnnotationConfigApplicationContext(
                                                PostConstructExample.class);
        ClientBean bean = context.getBean(ClientBean.class);
        bean.doSomething();
    }

    public static class ClientBean {
        private ServiceBean serviceBean;

        @PostConstruct
        public void myPostConstructMethod () throws Exception {
            // we can do more validation than just checking null values here
            if (serviceBean == null) {
                throw new IllegalArgumentException("ServiceBean not set");
            }
        }

        public void setServiceBean (ServiceBean serviceBean) {
            this.serviceBean = serviceBean;
        }

        public void doSomething () {
            System.out.println("doing something with: " + serviceBean);
        }
    }

    public static class ServiceBean {
    }
}

Output

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'clientBean': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: ServiceBean not set

Using Autowire.BY_TYPE mode:

package com.logicbig.example;

import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;

@Configuration
public class PostConstructAutoWiringByType {

    @Bean(autowire = Autowire.BY_TYPE)
    public ClientBean clientBean() {
        return new ClientBean();
    }

    //remove following comment to get rid of java.lang.IllegalArgumentException
    //@Bean
    public ServiceBean serviceBean() {
        return new ServiceBean();
    }

    public static void main(String... strings) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(
                        PostConstructAutoWiringByType.class);
        ClientBean bean = context.getBean(ClientBean.class);
        bean.doSomething();
    }

    public static class ClientBean {
        private ServiceBean serviceBean;

        public void setServiceBean(ServiceBean serviceBean) {
            this.serviceBean = serviceBean;
        }

        public void doSomething() {
            System.out.println("doing something with: " + serviceBean);
        }

        @PostConstruct
        public void myPostConstructMethod() throws Exception {
            // we can do more validation than just checking null values here
            if (serviceBean == null) {
                throw new IllegalArgumentException("ServiceBean not set");
            }
        }
    }

    public static class ServiceBean {
    }
}

Output

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'clientBean': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: ServiceBean not set

Example Project

Dependencies and Technologies Used:

  • spring-context 5.3.8: Spring Context. Version Compatibility: 4.3.0.RELEASE - 5.3.8 Version List
    ×

    Version compatibilities of spring-context with this example:

    • 4.3.0.RELEASE
    • 4.3.1.RELEASE
    • 4.3.2.RELEASE
    • 4.3.3.RELEASE
    • 4.3.4.RELEASE
    • 4.3.5.RELEASE
    • 4.3.6.RELEASE
    • 4.3.7.RELEASE
    • 4.3.8.RELEASE
    • 4.3.9.RELEASE
    • 4.3.10.RELEASE
    • 4.3.11.RELEASE
    • 4.3.12.RELEASE
    • 4.3.13.RELEASE
    • 4.3.14.RELEASE
    • 4.3.15.RELEASE
    • 4.3.16.RELEASE
    • 4.3.17.RELEASE
    • 4.3.18.RELEASE
    • 4.3.19.RELEASE
    • 4.3.20.RELEASE
    • 4.3.21.RELEASE
    • 4.3.22.RELEASE
    • 4.3.23.RELEASE
    • 4.3.24.RELEASE
    • 4.3.25.RELEASE
    • 4.3.26.RELEASE
    • 4.3.27.RELEASE
    • 4.3.28.RELEASE
    • 4.3.29.RELEASE
    • 4.3.30.RELEASE
    • 5.0.0.RELEASE
    • 5.0.1.RELEASE
    • 5.0.2.RELEASE
    • 5.0.3.RELEASE
    • 5.0.4.RELEASE
    • 5.0.5.RELEASE
    • 5.0.6.RELEASE
    • 5.0.7.RELEASE
    • 5.0.8.RELEASE
    • 5.0.9.RELEASE
    • 5.0.10.RELEASE
    • 5.0.11.RELEASE
    • 5.0.12.RELEASE
    • 5.0.13.RELEASE
    • 5.0.14.RELEASE
    • 5.0.15.RELEASE
    • 5.0.16.RELEASE
    • 5.0.17.RELEASE
    • 5.0.18.RELEASE
    • 5.0.19.RELEASE
    • 5.0.20.RELEASE
    • 5.1.0.RELEASE
    • 5.1.1.RELEASE
    • 5.1.2.RELEASE
    • 5.1.3.RELEASE
    • 5.1.4.RELEASE
    • 5.1.5.RELEASE
    • 5.1.6.RELEASE
    • 5.1.7.RELEASE
    • 5.1.8.RELEASE
    • 5.1.9.RELEASE
    • 5.1.10.RELEASE
    • 5.1.11.RELEASE
    • 5.1.12.RELEASE
    • 5.1.13.RELEASE
    • 5.1.14.RELEASE
    • 5.1.15.RELEASE
    • 5.1.16.RELEASE
    • 5.1.17.RELEASE
    • 5.1.18.RELEASE
    • 5.1.19.RELEASE
    • 5.1.20.RELEASE
    • 5.2.0.RELEASE
    • 5.2.1.RELEASE
    • 5.2.2.RELEASE
    • 5.2.3.RELEASE
    • 5.2.4.RELEASE
    • 5.2.5.RELEASE
    • 5.2.6.RELEASE
    • 5.2.7.RELEASE
    • 5.2.8.RELEASE
    • 5.2.9.RELEASE
    • 5.2.10.RELEASE
    • 5.2.11.RELEASE
    • 5.2.12.RELEASE
    • 5.2.13.RELEASE
    • 5.2.14.RELEASE
    • 5.2.15.RELEASE
    • 5.3.0
    • 5.3.1
    • 5.3.2
    • 5.3.3
    • 5.3.4
    • 5.3.5
    • 5.3.6
    • 5.3.7
    • 5.3.8

    Versions in green have been tested.

  • JDK 8
  • Maven 3.8.1

Spring - Required dependency checking Select All Download
  • spring-dependency-checking
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • PostConstructExample.java

    See Also