Why am I getting this "CONDITION EVALUATION DELTA" output? - spring

I made some changes on my server but I do not know which of these changes causes this log output:
==========================
CONDITION EVALUATION DELTA
==========================
Positive matches:
-----------------
None
Negative matches:
-----------------
SpringBootWebSecurityConfiguration:
Did not match:
- #ConditionalOnMissingBean (types: org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; SearchStrategy: all) found beans of type 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter' org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerSecurityConfiguration, org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration, webSecurityConfig (OnBeanCondition)
Matched:
- #ConditionalOnClass found required class 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter' (OnClassCondition)
- found 'session' scope (OnWebApplicationCondition)
UserDetailsServiceAutoConfiguration:
Did not match:
- #ConditionalOnMissingBean (types: org.springframework.security.authentication.AuthenticationManager,org.springframework.security.authentication.AuthenticationProvider,org.springframework.security.core.userdetails.UserDetailsService; SearchStrategy: all) found beans of type 'org.springframework.security.authentication.AuthenticationManager' authenticationManager and found beans of type 'org.springframework.security.core.userdetails.UserDetailsService' appUserDetailsService and found beans of type 'org.springframework.security.authentication.AuthenticationProvider' daoAuthenticationProvider (OnBeanCondition)
Matched:
- #ConditionalOnClass found required class 'org.springframework.security.authentication.AuthenticationManager' (OnClassCondition)
WebSecurityEnablerConfiguration:
Did not match:
- #ConditionalOnMissingBean (names: springSecurityFilterChain; SearchStrategy: all) found beans named springSecurityFilterChain (OnBeanCondition)
Matched:
- found 'session' scope (OnWebApplicationCondition)
Exclusions:
-----------
None
Unconditional classes:
----------------------
None
This is really not telling me anything.
What does it even mean? Is there something broken because the server is still working fine.

The condition evaluation delta is a feature of Spring Boot's DevTools. It is described in the documentation as follows:
By default, each time your application restarts, a report showing the condition evaluation delta is logged. The report shows the changes to your application’s auto-configuration as you make changes such as adding or removing beans and setting configuration properties.
In the case shown in your question, some changes were made to security-related beans which affected security auto-configuration. There is nothing broken. The output is attempting to help you to understand how the changes you are making to your application are affecting its auto-configuration.
You can turn off the logging of the delta if you wish. To do so, set the following property:
spring.devtools.restart.log-condition-evaluation-delta=false

This is generated when the log level for the application is set to trace or debug.

This can occur even if you did not make any changes. It appears to be a bug.
My authentication is disabled in a configuration class with permitAll() and works as expected 100% of the time when starting the application fresh.
However, when the restarter kicks in, I will frequently see a SpringBootWebSecurityConfiguration delta and, when I refresh my browser, I am presented with an erroneous login screen.
Doing another build (that actually changes something, in order to trigger the restarter) or an IntelliJ 'Update application', will usually show another delta (going from auto config, back to my config) and then the login screen is no longer presented. Usually, not always - sometimes takes 2 or I give up and stop+start.
As you can imagine, this is VERY frustrating. On the plus side, my app is very lightweight and there is very little difference between a stop+start and using the restarter. I am simply changing my habits and will be able to remove a dependency from my project!

Related

spring boot auto configuration. unexpected behaviour

I am trying to use spring boot auto configuration feature and got an issue.
I created a github repo to be able to reproduce easily the "issue":
git clone https://github.com/clembo590/issues.git --branch spring_boot_auto_configuration
just run mvn clean install and you will get all the logs I am refering to in my description.
I have "enabled" the debug=true spring boot property to see which 'autoconfiguration' is activated or not (and if it is not active why it is not active).
I also have added some logs to "log all the beans that have been added to the spring boot context".
Here is my autoConfiguration class.
#Configuration
#ComponentScan(basePackageClasses = MyClass.class)
#ConditionalOnBean(ObjectMapper.class)
#AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
public class CleaningAutoConfiguration {
#Bean
public Fake fake(){
return new Fake();
}
private static class Fake{
}
}
The very first weird thing is this log:
CleaningAutoConfiguration:
Did not match:
- #ConditionalOnBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) did not find any beans of type com.fasterxml.jackson.databind.ObjectMapper (OnBeanCondition)
Matched:
- #ConditionalOnBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) found bean 'jacksonObjectMapper' (OnBeanCondition)
First question:
Why is #ConditionalOnBean BOTH matching and Not matching ? (my expectation about such a condition is that it should either match or not match... but not both... see question 5)
Now if we look at the logs it seems that CleaningAutoConfiguration is in the Negative matches: section.
Second question:
why is CleaningAutoConfiguration itself registered as a bean ? (I was expecting it would not as it is in the Negative matches section).
Third question:
Why is fake still registered as a bean (I was expecting that fake would not be registered, and not even instanciated...)
Fourth question:
why is MyClass not registered as a bean ?
Now if you remove the #ComponentScan(basePackageClasses = MyClass.class) then all those questions go away as CleaningAutoConfiguration goes into Positive matches section, but one new is created:
fifth question:
Why removing the #ComponentScan brings CleaningAutoConfiguration into Positive matches section ? (maybe question 5 is somehow connected to question 1 .... ?)
The root cause of your problem is the use of #ComponentScan on an auto-configuration class which is not supported:
Furthermore, auto-configuration classes should not enable component scanning to find additional components. Specific #Imports should be used instead.
To answer your specific questions:
Why is #ConditionalOnBean BOTH matching and not matching
It's first evaluated as part of considering the unsupported #ComponentScan annotation. At this time, the ObjectMapper bean has not been defined so it does not match. It's subsequently evaluated after the ObjectMapper bean has been defined at which point it matches.
why is CleaningAutoConfiguration itself registered as a bean ? (I was expecting it would not as it is in the Negative matches section).
The report has mislead you here due to the positive and negative match. CleaningAutoConfiguration is a bean due to the positive match.
Why is fake still registered as a bean (I was expecting that fake would not be registered, and not even instanciated...)
The report has misled you again. The conditions on CleaningAutoConfiguration have been matched so its Fake bean has been defined.
why is MyClass not registered as a bean
The conditions on CleaningAutoConfiguration did not match when the #ComponentScan annotation was being considered so component scanning of MyClass's package was not enabled.
Why removing the #ComponentScan brings CleaningAutoConfiguration into Positive matches section
It prevents the conditions on CleaningAutoConfiguration being evaluated prematurely at a time when the ObjectMapper bean has not yet been defined. When they are eventually evaluated at the expected time, the ObjectMapper bean is present and the conditions match.

How can I exclude the conditions evaluation report from the console of a Spring boot application?

When I run my Spring boot application, I get the conditions evaluation report in my console logs.
How can I disable or exclude this report from my console logs in Spring boot?
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
AopAutoConfiguration matched:
- #ConditionalOnClass found required classes 'org.springframework.context.annotation.EnableAspectJAutoProxy', 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice', 'org.aspectj.weaver.AnnotatedElement'; #ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- #ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
AopAutoConfiguration.CglibAutoProxyConfiguration matched:
- #ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)
CacheAutoConfiguration matched:
- #ConditionalOnClass found required class 'org.springframework.cache.CacheManager'; #ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- #ConditionalOnBean (types: org.springframework.cache.interceptor.CacheAspectSupport; SearchStrategy: all) found bean 'cacheInterceptor'; #ConditionalOnMissingBean (names: cacheResolver; types: org.springframework.cache.CacheManager; SearchStrategy: all) did not find any beans (OnBeanCondition)
...
You can do this by changing the log level of org.springframework.boot.autconfigure. For example by adding the following line within application.properties:
logging.level.org.springframework.boot.autoconfigure=ERROR
You'll get the condition outcome report if you:
Configure your IDE to show debug output (for example, if you set Enable debug output within a Spring boot run configuration in IntelliJ).
Set the property debug=true within application.properties.
Set the logging level of org.springframework.boot.autoconfigure.logging to DEBUG.
This can be useful when you're trying to find out why certain beans are not being loaded, because with this report you can see exactly which autoconfiguration is being loaded, and which one isn't (and why).
You can disable this output by undoing the earlier mentioned bullet points. For example, you could set the logging level of org.springframework.boot.autoconfigure.logging to INFO:
logging.level.org.springframework.boot.autoconfigure.logging=INFO
While the other answer works, it's also possible to set the log level to INFO:
logging.level.org.springframework.boot.autoconfigure=INFO
just add to application.yml the following
logging:
level:
ROOT: INFO
you/package/path: INFO
If you have application.yml the answer is
logging:
level:
org.springframework.boot: ERROR

Gemfire NoSuchBeanDefinitionException Autowiring Cache (Spring 5.0.2 / Gemfirev9.2.7)

We are migrating from Gemfire 8.2.7 to 9.2.1
As part of Gemfire startup, we leverage SpringContextBootstrappingInitializer to initialize the spring-beans which #Autowire the Cache.
The same code when migrated to Gemfire 9.2.1 (along with the other stack) is failing on server startup with below error.
Gemfire 8.2.7 --> Gemfire 9.2.1
Spring-data-Gemfire 1.8.4 --> 2.0.2
Spring-Boot 1.4.7 --> 2.0.0.M7
Spring --> 5.0.2
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'org.apache.geode.cache.Cache' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Any pointers / changes required for GemfireConfig? Below is our JavaConfig.
#Bean
public CacheFactoryBean gemfireCache() {
return new CacheFactoryBean();
}
Looks like the ComponentScan is kicking in prior to Configuration processor. Any idea on controlling this behavior? This was lasted tested to work in Spring-Boot 1.4.6 (Spring- 4.3.8) and gets resolved with a #Depends option - but just wanted to understand if there are any fundamental changes with the ordering of bean initialization with newer Spring version.
#Configuration
#EnableAutoConfiguration(exclude = { HibernateJpaAutoConfiguration.class, BatchAutoConfiguration.class })
#Import(value = { GemfireServerConfig.class, JpaConfiguration.class, JpaConfigurableProperties.class })
#ComponentScan(basePackages = "com.test.gemfire", excludeFilters = #ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class) )
To begin, let me give you some tips since there are 3 issues with your problem statement above...
1) First, you have not made it clear why or how you are using the o.s.d.g.support.SpringContextBootstrappingInitializer Docs here.
I can only assume it is because you are launching your GemFire servers with Gfsh
using the following command...
gfsh> start server --name=MyServer --cache-xml-file=/path/to/cache.xml ...
Where your cache.xml is defined similar to this. After all, this was the original intent for using the SpringContextBootstrappingInitializer.
If this is the case, why not use the Gfsh, start server command, --spring-xml-location option instead. For example:
gfsh> start server --name=MyServer --spring-xml-location=/by/default/a/classpath/to/applicationContext.xml --classpath=/path/to/spring-data-gemfire-2.0.2.RELEASE.jar:...
By doing so, you no longer need to provide cache.xml just to declare the SpringContextBootstrappingInitializer in order to bootstrap a Spring container inside the GemFire JVM process. You can simply use the --spring-xml-location option and put SDG on the server's classpath when starting the server.
2) Second, it is not apparent what type of application component/bean you are injecting a GemFire Cache reference into (e.g. a Region or another application component class, like a DAO, etc). Providing a snippet of code showing how you injected the Cache reference, i.e. the injection point using the #Autowired annotation would have been helpful. For example:
#Service
class MyService {
#Autowired
private Cache gemfireCache;
...
}
3) #2 would have been more apparent if you included the full stack trace rather than just the NoSuchBeanDefinitionException message.
Despite the issues with your problem statement, I can infer the following:
Clearly, you are using "classpath component scanning" (with the #ComponentScan annotation) and are auto-wiring "by type"; which maybe key actually; I will come back to this later below.
You are using Spring's #Autowired annotation on a bean class field (field injection) or property (setter injection), maybe even a constructor.
The type of this field/property (or constructor parameter) is definitely org.apache.geode.cache.Cache.
Moving on...
In general, Spring will follow dependency order first and foremost. That is, if A depends on B, then B must be created before and destroyed after A. Typically, Spring will and can honor this without incident.
Beyond "dependency order" bean creation and satisfying dependencies between beans (including with the #DependsOn annotation), the order of bean creation is pretty loosely defined.
There are several factors that can influence it, such as "registration order" (i.e. the order in which bean definitions are declared, which is particularly true for beans defined in XML), "import order" (when using the #Import annotation on #Configuration classes), Java reflection (includes #Bean definitions declared in #Configuration classes), etc. Configuration organization is definitely important and should not be taken lightly.
This is 1 reason why I am not a big proponent of "classpath component scanning. While it may be convenient, it is always better, IMO, to be more "explicit" in your configuration, and the organization of your configuration, for reasons outlined here in addition to other non-apparent limitations. At worst, you should definitely be limiting the scope of the scan.
Ironically, you excluded/filtered the 1 thing that could actually help your organizational concerns... components of type #Configuration:
... excludeFilters = #ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
NOTE: given the exclusion, are you certain you did not exclude the the 1 #Configuration class containing your CacheFactoryBean definition? I suppose not since you say this worked after including the #DependsOn annotation.
Clearly there is a dependency defined between some application component of yours (??) and a bean of type o.a.g.cache.Cache (using #Autowired), yet Spring is failing to resolve it.
My thinking is, Spring cannot resolve the Cache dependency because 1) the GemFire cache bean either has not been created yet and 2) Spring cannot find an appropriate bean definition of the desired type (i.e. o.a.g.cache.Cache) in your configuration that would resolve the dependency and force the GemFire Cache to be created first, or 3) the GemFire Cache bean has been created first but Spring is unable to resolve the type as o.a.g.cache.Cache.
I have encountered both scenarios before and it is not exactly clear to me when each scenario happens because I simply have not traced this through yet. I have simply corrected it and moved on. I have noticed that it is version related though.
There are several ways to solve this problem.
If the problem is the later, 3), then simply declaring your dependency as type o.a.g.cache.GemFireCache should resolve the problem. So, for example:
#Repository
class MyDataAccessObject {
#Autowired
private GemFireCache gemfireCache;
...
}
The reason for this is because the o.s.d.g.CacheFactoryBean class's getObjectType() method returns a Class type generically extending o.a.g.cache.GemFireCache. This was by design since o.s.d.g.client.ClientCacheFactoryBean extends o.s.d.g.CacheFactoryBean, though I probably would not have done it that way if I had created these classes. However, it is consistent with the fact that the actual cache type in GemFire is o.a.g.internal.cache.GemFireCacheImpl which indirectly implements both the o.a.g.cache.Cache interface as well as the o.a.g.cache.client.ClientCache interface.
If your problem is the former (1) + 2), which is a bit trickier), then I would suggest you employ a smarter organization of your configuration, separated by concern. For example, you can encapsulate your GemFire configuration with:
#Configuration
class GemFireConfiguration {
// define GemFire components (e.g. CacheFactoryBean) here
}
Then, your application components, where some are dependent on GemFire components, can be defined with:
#Configuration
#Import(GemFireConfiguration.class)
class ApplicationConfiguration {
// define application beans, including beans dependent on GemFire components
}
By importing the GemFireConfiguration you are ensuring the GemFire components/beans are created (instantiated, configured and initialized) first.
You can even employ more targeted, limited "classpath component scanning" at the ApplicationConfiguration class-level in cases where you have a large number of application components (services, DAO, etc).
Then, you can have your main, Spring Boot application class drive all this:
#Configuration
#Import(ApplicationConfiguration.class)
class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class, args);
}
}
The point is, you can be as granular as you choose. I like to encapsulate configuration by concern and clearly organize the configuration (using imports) to reflect the order in which I want my components created (constructed, configured and initialized).
Honestly, I basically organize my configuration in the order of dependencies. If my application ultimately depends on a data store and cannot function without that data store, then it makes since to ensure that is initialized first, otherwise, what is the point of starting the application.
Finally, you can always rely on the #DependsOn annotation, as you have appropriately done, to ensure that Spring will create the component before the component that expects it.
Based on the fact that the #DependsOn annotation solved your problem, then I would say this is an organizational problem and falls under the 1) / 2) category I outlined above.
I am going to dig into this a bit deeper and respond to my answer in comments with what I find.
Hope this helps!
-John

JaversSqlAutoConfiguration.javers() not getting called

Context
I have used #TypeName("Employee") for my entities so I can lose the fully qualified TypeName in DB. It works as expected.
Issue
When the Spring boot application is restarted and there are existing audit logs, I get TYPE_NAME_NOT_FOUND exception when I hit javers.findSnapshots()
org.javers.common.exception.JaversException: TYPE_NAME_NOT_FOUND type name 'Employment' not found. If you are using #TypeName annotation, remember to register this class using JaversBuilder.scanTypeName(Class). See also https://github.com/javers/javers/issues/263
My Approach so far
I have added JaversSqlAutoConfiguration.java, call it MyJaversSqlAutoConfiguration.
I then added scanTypeName(Employee.class) in MyJaversSqlAutoConfiguration.javers().
Observation
I noticed MyJaversSqlAutoConfiguration.javers(connectionProvider) doesn't get hit. However, org.javers.spring.boot.sql.JaversSqlAutoConfiguration.javers() gets hit in debug mode. commitPropertiesProvider() and springSecurityAuthorProvider() in MyJaversSqlAutoConfiguration' gets hit. But notMyJaversSqlAutoConfiguration.javers(ConnectionProvider connectionProvider)`.
Upon closer inspection, I found that org.javers.spring.boot.sql.JaversSqlAutoConfiguration.javers() doesn't have #ConditionalOnMissingBean but commitPropertiesProvider() and springSecurityAuthorProvider() do.
Question
Is there a working example of this scanTypeName() somewhere or should we add #ConditionalOnMissingBean?
Looks like #ConditionalOnMissingBean is missing in javers bean defintions (in both javers-spring-boot-starters).
It can be added to JaversSqlAutoConfiguration.java and JaversMongoAutoConfiguration.java
#Bean(name = "javers")
#ConditionalOnMissingBean
public Javers javers(ConnectionProvider connectionProvider) {
...
If you contribute a PR, we will merge it.

2 beans with same name but in different packages; how to autowire them?

I have an application that has 2 beans with the same name, but which are in different packages. My Spring application fails because it cannot decide on which bean to take. Is there any solution for this? The beans do not currently implement specific interfaces.
See below an edited example of the exception:
Caused by:
org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'dataTransferHandler' for bean class
[aaaaa.ws.handler.DataTransferHandler] conflicts with existing,
non-compatible bean definition of same name and class
[bbbbb.ws.handler.DataTransferHandler]
You will have to give your beans different names - if multiple beans are defined with the same name, then the one defined later will override the one defined earlier - so in your case only one bean will exist with the name of dataTransferHandler.
You can give these two beans different names, so that both can exist and you can inject in the correct one either using:
#AutoWired #Qualifier("dataTransferHandler")
OR
#Resource(name="dataTransferHandler")
You can give attribute primary="true" to the bean defination you want to have the preference when autowired. But the bean names must be different. There is no solution for same bean name.
At run-time when you will get the autowired class then the primary true bean will get the preference for autowiring. Hope this helps you. Cheers.
I asked another question regarding the same problem, and there is a solution that doesn't require using the #Qualifier annotation: if both of your DataTransferHandler classes have a #Component annotation, you can simply add a String argument to one of their constructions (i.e. #Component("Foo")), and that should solve the problem without needing additional changes.
See User9123's answer on my question for more details.

Resources