Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting unused Spring beans

Given a Spring configuration that exclusively contains eager (non-lazy) singleton beans, i.e. the defaults, is it possible to have Spring throw an exception in the case where any of those beans is not injected anywhere? I'm essentially looking for a way to detect dead code in the form of Spring beans.

My question is somewhat similar to these.

  • http://forum.spring.io/forum/spring-projects/container/116494-any-tools-or-method-to-identify-unused-spring-beans
  • Spring Instantiation and 'unused beans'
  • How to detect unused properties in Spring

However,

  • I'm not interested in manually inspecting a graph or parsing log data.
  • I don't have the added complexity of multiple context files, overriding beans, bean post-processing, or xml. It's a simple, straightforward, annotation-driven configuration.
  • I'm using Spring Boot 1.2.6 which is several years newer than those questions (maybe new functionality exists).

Spring will certainly throw an exception if a necessary bean is missing. Can it also throw an exception in the opposite scenario where a bean is found but unnecessary?

like image 991
jaco0646 Avatar asked Mar 16 '16 22:03

jaco0646


People also ask

How do you test spring beans?

To test whether Spring MVC controllers are working as expected, use the @WebMvcTest annotation. To test that Spring WebFlux controllers are working as expected, you can use the @WebFluxTest annotation. You can use the @DataJpaTest annotation to test JPA applications.

How do you inject beans in the spring?

In Spring Boot, we can use Spring Framework to define our beans and their dependency injection. The @ComponentScan annotation is used to find beans and the corresponding injected with @Autowired annotation. If you followed the Spring Boot typical layout, no need to specify any arguments for @ComponentScan annotation.


1 Answers

Spring will certainly throw an exception if a necessary bean is missing. Can it also throw an exception in the opposite scenario where a bean is found but unnecessary?

TL/DR:

Spring does not support this (and probably never will).

Long version:

Detecting if a bean is used can be really hard.

First, lets define when does spring throw the "missing bean" exception.

During the initialisation of the spring context, spring creates the beans in the order in which it will allow for all dependencies to be satisfied (if possible). If a bean is missing a dependency, spring will throw an exception (as you said). So, the exception is thrown during the spring context initialisation process.

Now, you could say that we could monitor this process and look for a bean that was not used as a dependency in any other bean. The problem is that not all bean dependencies are defined during the spring context initialisation process.

Let's look at the following example:

First, we have a simple interface, DataService

public interface DataService {
 String getData();
}

Now we have 2 spring beans that implement this interface:

@Service("firstDataService")
public class FirstDataService implements DataService {

  @Override
  public String getData() {
    return "FIRST DATA SERVICE";
  }
}

@Service("secondDataService")
public class SecondDataService implements DataService {
  @Override
  public String getData() {
    return "SECOND DATA SERVICE";
  }
}

Now, imagine that there is no bean that depends on these two beans directly. When I say directly, I mean there is no bean that depends on these beans via constructor-based, setter-based or field-based dependency injection.

Because of that, spring will not inject these beans inside any other bean during the context initialisation process.

Now, consider the following bean:

@Service
public class DataCollector {

  @Autowired
  ApplicationContext applicationContext;


  String getDataFromService(String beanName) {
    DataService ds = (DataService) applicationContext.getBean(beanName);
    return ds.getData();
  }
}

If I call the getDataFromService method of the DataCollector bean with "firstDataService" value for the beanName parameter, the method will return "FIRST DATA SERVICE" as a result. If I call the method with "secondDataService", I will return "SECOND DATA SERVICE" as a result.

Now, when spring looks at the definition of DataController during context initialisation, there is no way to determine on which beans DataCollector depends on. It all depends on the application logic, and the value that we use for the beanName parameter when we call the getDataFromService method.

Because of that, spring is not capable of determining if there is bean that is never used (because the bean usage can be dynamic, like in the case above).

like image 157
Dimitar Spasovski Avatar answered Oct 13 '22 20:10

Dimitar Spasovski