CacheAutoConfiguration is not working due to CacheAspectSupport not found - spring-boot

I'm using springboot 2.1.1.
I enabled cache with #EnableCaching
A CacheManager is created and can be injected in my classes.
Once I add a library https://github.com/MarcGiffing/bucket4j-spring-boot-starter
I've got an error when starting the application :
java.lang.IllegalStateException: No CacheResolver specified, and no bean of type CacheManager found. Register a CacheManager bean or remove the #EnableCaching annotation from your configuration.
at org.springframework.cache.interceptor.CacheAspectSupport.afterSingletonsInstantiated(CacheAspectSupport.java:227)
After a lot of debugging, I can't find why and how the library is breaking the CacheManager.
It seems like the CacheAutoConfiguration spring class is not used :
CacheAutoConfiguration:
Did not match:
- #ConditionalOnBean (types: org.springframework.cache.interceptor.CacheAspectSupport; SearchStrategy: all) did not find any beans of type org.springframework.cache.interceptor.CacheAspectSupport (OnBeanCondition)
Matched:
- #ConditionalOnClass found required class 'org.springframework.cache.CacheManager' (OnClassCondition)
But I added a breakpoint in ProxyCachingConfiguration#L63 and an instance of CacheInterceptor (CacheAspectSupport impl) is created.
I can inject it in one of my Configuration class. So the bean CacheAspectSupport seems to exist in the application context.
So why the CacheAutoConfiguration says the bean is missing ?
Thanks

I found out why.
My Configuration class holding the #EnableCaching annotation was loaded too late when the library was added.
I added a #AutoConfigureBefore(CacheAutoConfiguration.class) and It is now working.

Related

How does Spring boot put Thymeleaf view resolver into its bean container

It is a spring boot project and the web page is rendered by Thymeleaf. When I put spring-boot-starter-thymeleaf in the pom.xml and start the applicaiton, it is trying to find all the beans which implements ViewResolver in its container. And you see here it find thymeleafViewResolver.
I am just curious that when and how does Spring boot put this ThymeleafViewResolver class into its bean container?
It is due to SpringBoot auto-configuration feature which will automatically create a bean dynamically based on different conditions such as if a library can be found from the class paths, or if developers already define a bean of certain type etc...
If you turn on the debug mode by putting debug=true in the application.properties , it will print out a report during application startup saying which beans are auto created due to which conditions.
In the example of the spring-boot-starter-thymeleaf , you can find the following from the report :
ThymeleafAutoConfiguration.ThymeleafWebMvcConfiguration.ThymeleafViewResolverConfiguration#thymeleafViewResolver matched:
- #ConditionalOnMissingBean (names: thymeleafViewResolver; SearchStrategy: all) did not find any beans (OnBeanCondition)
And by tracing the source codes of ThymeleafViewResolverConfiguration :
#Bean
#ConditionalOnMissingBean(name = "thymeleafViewResolver")
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(this.templateEngine);
resolver.setCharacterEncoding(this.properties.getEncoding().name());
//.......
return resolver;
}
You could find out thymeleafViewResolver is in a type of ThymeleafViewResolver and #ConditionalOnMissingBean here means that this bean will only be created if there is no bean of the ThymeleafViewResolver type is defined yet.

Spring Boot disable creation of JpaProperties configuration in WAR deployment

I'm trying to setup a Spring Boot application that uses EclipseLink instead of Hibernate. The project has a similar structure to this example project:
https://github.com/spring-projects/spring-data-examples/blob/master/jpa/eclipselink/src/main/java/example/springdata/jpa/eclipselink/Application.java
The main difference is that our application needs to be packaged as a WAR... so the main Application.java extends SpringBootServletInitializer instead of the JpaBaseConfiguration shown in the example (we have another bean with #Configuration that extends JpaBaseConfiguration).
When the app starts it encounters a ClassNotFoundException for the a naming strategy that comes form Hibernate:
Error creating bean with name 'spring.jpa-org.springframework.boot.autoconfigure.orm.jpa.JpaProperties': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/hibernate/boot/model/naming/ImplicitNamingStrategy
It seems that this only happens when the application extends from SpringBootServletInitializer.
Turning on debug shows this:
JpaBaseConfiguration.JpaWebConfiguration:
Did not match:
- #ConditionalOnProperty (spring.jpa.open-in-view=true) found different value in property 'open-in-view' (OnPropertyCondition)
Matched:
- #ConditionalOnClass found required class 'org.springframework.web.servlet.config.annotation.WebMvcConfigurer'; #ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- found ConfigurableWebEnvironment (OnWebApplicationCondition)
Is there any way to exclude the JpaWebConfiguration, but still have the application extend from SpringBootServletInitializer?
UPDATE: After debugging this further I don't believe the JpaWebConfiguration is the issue as that is in the unmatched section of the debug, but something is still causing the creation of a JpaProperties bean and hitting the ClassNotFoundException.

Spring Boot MessageSourceAutoConfiguration

I have a problem or possibly I found a bug in Spring Boot. I am not sure at the moment.
I have a project with the following dependencies
spring-boot-starter-thymeleaf
spring-boot-starter-web
spring-boot-starter-actuator
spring-boot-starter-mail
spring-cloud-starter-bus-amqp
spring-cloud-starter-config
spring-cloud-starter-eureka
I want to use a messageSource in my Thymeleaf templates and so I set the following in my application.yml:
spring:
messages:
basename: de/mycompany/messages/message
and placed a message.properties and a message_de.properties in the above package. But the replacing did not work.
So I debugged MessageSourceAutoConfiguration and found, that the #Conditional(ResourceBundleCondition.class) did work. It found my Resources and returned true.
So I let print the debug report and found, that it says
MessageSourceAutoConfiguration
- Bundle found for spring.messages.basename: de/mycompany/messages/message (MessageSourceAutoConfiguration.ResourceBundleCondition)
- #ConditionalOnMissingBean (types: org.springframework.context.MessageSource; SearchStrategy: all) found the following [messageSource] (OnBeanCondition)
So there is another messageSource Bean already defined, but i wondered where it did come from. So i investigated further and found the following log output:
AnnotationConfigEmbeddedWebApplicationContext : Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource#60df7989]
In fact it comes from the class AbstractApplicationContext in method initMessageSource (around line 622).
There it checks for a bean with name "messageSource" and if it doesn't find one, it creates the above mentioned DelegatingMessageSource.
Am I missing something? Do I have to do something to get the MessageSourceAutoConfiguration happen before this AbstractApplicationContext stuff? Or is this really a bug?
For myself I fixed it by simply creating the messageSource myself as a #Bean, but using the AutoConfiguration would be far smarter :)
Greetings Christian
Turns out this is a bug, hopefully it gets resolved soon, tracked here:
https://github.com/spring-cloud/spring-cloud-commons/issues/29

How do you get a transaction manager in a non web Spring Boot Appllication?

Is there a quick and easy way to get a ComamandLineRunner app to have a transaction manager? I have the following setup:
#EnableAutoConfiguration(exclude={WebMvcAutoConfiguration.class})
and
spring.main.web_environment=false
in the application.properties. When I run the code:
ConfigurableApplicationContext context = application.run();
context.close();
I see this:
2014-10-26 11:00:59.956 INFO 4900 --- [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
I see SQL echo out from the JPA Repository I've made but no transaction is committed to the db. I've tried moving things into a service, making things as #Transactional etc. I don't seem to be getting one popping into existence.
Update 1:
In case it matters I am using 1.2.0.M2. I suspect #EnableAutoConfiguration still isn't doing the trick. The debug output has this:
JpaBaseConfiguration#entityManagerFactory
- #ConditionalOnMissingBean (types: org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; SearchStrategy: all) found no beans (OnBeanCondition)
JpaBaseConfiguration#entityManagerFactoryBuilder
- #ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilder; SearchStrategy: all) found no beans (OnBeanCondition)
JpaBaseConfiguration#jpaVendorAdapter
- #ConditionalOnMissingBean (types: org.springframework.orm.jpa.JpaVendorAdapter; SearchStrategy: all) found no beans (OnBeanCondition)
JpaBaseConfiguration#transactionManager
- #ConditionalOnMissingBean (types: org.springframework.transaction.PlatformTransactionManager; SearchStrategy: all) found no beans (OnBeanCondition)
The application.properties have a spring.datasource setup and Hibernate is getting the right dialect. I have created a #Service class with a method marked as #Transactional. It still isn't getting commited however.
Spring Boot will automatically create a transaction manager when configuring JPA. Check out method transactionManager in class JpaBaseConfiguration.
Note that this setup has nothing to do with the fact that the application is a web application or not.
So using #Transactional on Spring Beans will work correctly

conflicts with existing, non-compatible bean definition of same name and class after proguard obfuscation

after Proguard obfuscation i get the following error :
Unexpected exception parsing XML document from ServletContext resource
[/WEB-INF/applicationContext.xml]; nested exception is
java.lang.IllegalStateException: Annotation-specified bean name 'a'
for bean class [com.company.project.b.a.a.a] conflicts with existing,
non-compatible bean definition of same name and class
[com.company.project.a.a]
i'm using annotation based spring configuration , how can i avoid having two classes with the same name using Proguard because Spring doesn't allow two beans to have the same name.
I'm not sure if this is what you want, but you can specify bean name in #Component (and stereotypes #Repository, #Service and #Controller) value:
#Component("myBeanName")
public class MyBean {
}
I had the same problem and nothing else was helping out. Sometimes the problem occurs if you have moved your classes around and it refers to old classes, even if they don't exist.
In this case, just do this :
mvn eclipse:clean
mvn eclipse:eclipse
This worked well for me.
Another cause; you may have different versions of Spring in your classpath, for example, spring 2.x with spring 3.x. In such condition, beans seem to be loaded twice. If you use maven, check if a module does not import an old version of Spring (mvn dependency:tree) and remove it by excluding the involved spring artifact (exclusions).

Resources