jumping_monkey
jumping_monkey

Reputation: 7865

Error upgrading Spring Boot 2.2.7 to Spring Boot 2.3.0

I was using Spring Boot 2.2.7.RELEASE and everthing was working well. When i upgraded to Spring Boot 2.3.0.RELEASE, a few issues start to show up, i was able to resolve them except for this.

I have this class:

@Configuration
@EnableCaching
public class CacheConfiguration extends CachingConfigurerSupport {

    public static final String PROPERTY_RESOLVING_CACHE_RESOLVER_BEAN_NAME = "propertyResolvingCacheResolver";

    @Value("${my.cache.name}")
    private String myCacheName;

    @Autowired
    private Environment environment;

    @Bean(PROPERTY_RESOLVING_CACHE_RESOLVER_BEAN_NAME)
    @Override
    public CacheResolver cacheResolver() {
        return new PropertyResolvingCacheResolver(cacheManager(), environment);
    }

    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache(myCacheName))); 
        return cacheManager;
    }
}

and the error i am getting is this:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'environment' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:814)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1282)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:297)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$ShortcutDependencyDescriptor.resolveShortcut(AutowiredAnnotationBeanPostProcessor.java:796)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1238)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1226)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.resolvedCachedArgument(AutowiredAnnotationBeanPostProcessor.java:601)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.access$000(AutowiredAnnotationBeanPostProcessor.java:131)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:631)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
    ... 66 common frames omitted

I thought it was an issue with the 'life-cycle' of the beans, and i was auto-wiring too early, so i did this:

public class CacheConfiguration extends CachingConfigurerSupport implements EnvironmentAware {
 ...
 private Environment environment;
 ...
    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
 ...

But then, other issues start showing(after doing the above) like:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:814)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1282)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:297)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor.postProcessBeforeInitialization(ConfigurationClassPostProcessor.java:456)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595)
    ... 45 common frames omitted

This is getting out of my league, any help would be much appreciated, thanks!

Edit 1:
After experimenting a bit, the issue is because the creation of this bean @Bean(PROPERTY_RESOLVING_CACHE_RESOLVER_BEAN_NAME) is deferred to a later time.

It used to be created after cacheManager, but in 2.3.0.RELEASE, it's not anymore.

Edit 2:
DataSourceHealthIndicator is in the application context under bean name dbHealthContributor for both 2.2.7.RELEASE & 2.3.0.RELEASE.

This can be seen under /actuator/beans :

 "dbHealthContributor": {
     "aliases": [],
     "scope": "singleton",
     "type": "org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator",
     "resource": "class path resource [org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.class]",
     "dependencies": [
         "dataSource"
     ]
 },

Upvotes: 1

Views: 2010

Answers (2)

Yovi
Yovi

Reputation: 23

A bit late to the game, but I ran into the same problem when upgrading Spring Boot from 2.2.0 to 2.3.0. You could also solve the problem by using Spring's @Lazy annotation. That way the DataSourceHealthIndicator would be autowired later when it actually gets used and by that time the autoconfiguration would make it available for autowiring. And you wouldn't have to define your own bean like you did in your answer.

So instead of

@Autowired
private DataSourceHealthIndicator dataSourceHealthIndicator;

, you would use

@Autowired
@Lazy
private DataSourceHealthIndicator dataSourceHealthIndicator;

Upvotes: 1

jumping_monkey
jumping_monkey

Reputation: 7865

By having trace=true in application.properties, i managed to pin-point the issue.

I used to have this working(provided for free by Spring Boot):

@Autowired
private DataSourceHealthIndicator dataSourceHealthIndicator;

But it seems that dataSourceHealthIndicator 's creation has been delayed so that when my bean(that needs it) is being created, it couldn't find it and autowiring failed.

I therefore created it manually:

@Bean
@Primary
public DataSourceHealthIndicator dataSourceHealthIndicator(DataSource dataSource) {

    return new DataSourceHealthIndicator(dataSource, "SELECT 1 FROM DUAL");
}

and my error is gone.

I hope to be able to understand what happened to dataSourceHealthIndicator between 2.2.7.RELEASE and 2.3.0.RELEASE. I do not see anything mention about it in the Spring-Boot-2.3-Release-Notes or i have missed it, but i can still see it being "created" - see my Edit 2 in my question.

Upvotes: 1

Related Questions