Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What if SpringBoot auto-configuration fails?

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

Editor to share with you what to do about the failure of SpringBoot automatic configuration. I hope you will get something after reading this article. Let's discuss it together.

Problem description

Here is a simple reproduced code snippet. If you can make the right judgment when you haven't finished reading this article, congratulations on saving time reading this article.

1. Automatic configuration class: AutoTestConfiguration

Configuration@EnableConfigurationProperties (TestProperties.class) @ ConditionalOnProperty (prefix = "test", name = "enable") public class AutoTestConfiguration {@ Bean @ ConditionalOnMissingBean public TestBean testBean (TestProperties properties) {System.out.println ("this is executed."); return new TestBean ();}}

2. Configuration class TestProperties

@ ConfigurationProperties (prefix = "test") public class TestProperties {private boolean enable = true; public boolean isEnable () {return enable;} public void setEnable (boolean enable) {this.enable = enable;}}

Both of these classes are under root package and are guaranteed to be scanned by Spring; the question is, will TestBean be created normally? Of course, the conclusion here is no.

Some students may say that your TestProperties is not annotated with @ Configuration, and Spring does not recognize it. Is that really the case? Apparently not.

In the process of troubleshooting this problem, there are other problems that have not been encountered before; even if I have seen the Spring source code many times, there will still be some unexpected places for you; here is the problem, take your time to unveil it.

@ EnableConfigurationProperties comment behavior

In previous versions, TestProperties was annotated with the @ Configuration annotation

@ Configuration / / can be scanned by spring @ ConfigurationProperties (prefix = "test") public class TestProperties {private boolean enable = true; public boolean isEnable () {return enable;} public void setEnable (boolean enable) {this.enable = enable;}}

The general idea is that when the TestProperties is scanned, test.enable=true 's KMuv exists in the spring env, and when the AutoTestConfiguration automatic configuration class refresh is performed, @ ConditionalOnProperty (prefix = "test", name = "enable") takes effect, and the TestBean is created normally.

But this is not the case. Here is the verification of this problem.

Configuration is valid, AutoTestConfiguration is not refreshed

Two points:

AutoTestConfiguration#testBean execution outputs a log (used to determine whether the AutoTestConfiguration is refreshed properly)

Listen for ApplicationReadyEvent events and get the test.enable value (used to determine whether the configuration is loaded normally, that is, whether the TestProperties is refreshed normally)

The code is as follows:

@ SpringBootApplicationpublic class Application implements ApplicationListener {@ Autowired private ApplicationContext applicationContext; public static void main (String [] args) {SpringApplication.run (Application.class, args);} @ Override public void onApplicationEvent (ApplicationReadyEvent event) {System.out.println (this.applicationContext.getEnvironment (). GetProperty ("test.enable") + "-");}}

The result of execution is that AutoTestConfiguration#testBean is not executed, but test.enable is true.

This shows that TestProperties is refreshed, but it does not work on @ ConditionalOnProperty, so you can basically guess that it is the order of @ ConditionalOnProperty and @ EnableConfigurationProperties on the automatic configuration class.

Before verifying the order problem, I tried to add the following configuration to application.properties, the re run project:

Test.enable=true

Here I get another problem of bean conflicts.

Prefix-type

The exception prompts are as follows:

Parameter 0 of method testBean in com.glmapper.bridge.boot.config.AutoTestConfiguration required a single bean, but 2 were found:

-testProperties: defined in file [/ Users/glmapper/Documents/project/exception-guides/target/classes/com/glmapper/bridge/boot/config/TestProperties.class]

-test-com.glmapper.bridge.boot.config.TestProperties: defined in null

Here comes the bean of test-com.glmapper.bridge.boot.config.TestProperties, the name. I tried to check in the code to see if the given bean name was displayed, but I couldn't find it. There's only one possibility that this was created by spring itself.

This process was very advanced in the spring refresh phase, and it still took some time to troubleshoot the problem, and finally the problem was found before the beandefinitions initialization.

Here is a behavior of @ EnableConfigurationProperties annotation, which relies on EnableConfigurationPropertiesRegistrar. The source code is as follows:

Class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {.getQualifiedAttributeName (EnableConfigurationPropertiesRegistrar.class, "methodValidationExcludeFilter"); @ Override public void registerBeanDefinitions (AnnotationMetadata metadata, BeanDefinitionRegistry registry) {registerInfrastructureBeans (registry); registerMethodValidationExcludeFilter (registry); ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar (registry); / / to register getTypes (metadata) .forEach (beanRegistrar::register);}

It is easy to see from the code that EnableConfigurationPropertiesRegistrar registers the target metadata as bean; to continue debug, and finds the bean that produces the prefix-type format name.

Here is the specific code for getName

Private String getName (Class type, MergedAnnotation annotation) {/ / take prefix String prefix = annotation.isPresent ()? Annotation.getString ("prefix"): "; / / prefix +"-"+ Class fully qualified name return (StringUtils.hasText (prefix)? Prefix + "-" + type.getName (): type.getName ();}

At this point, let's make one question clear:

If you use @ EnableConfigurationProperties to open the configuration class, do not use annotations such as @ Configuration on the configuration class that can be recognized by Spring scan to avoid multiple instances of bean of the same type in subsequent use

@ ConditionalOnProperty

Coming back to the problem that the configuration does not take effect, it is recorded here in the official issue: github.com/spring-proj …

However, the root cause of the problem is restored by analyzing the code; it is mainly analyzed from two aspects:

The @ ConditionalOnProperty match value logic needs to be clear about which PropertySource is read from when matching the value.

@ ConditionalOnProperty match failure and bean refresh logic

@ ConditionalOnProperty match logic

First of all, @ ConditionalOnProperty matches the value sources of value when performing calculations. All source sources can be easily obtained through debug code, as shown in the following figure:

From the perspective of debug, there are four sources in this case (as shown in the figure above). In fact, in terms of source code, source covers all sources of spring env:

[ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, StubPropertySource {name='servletConfigInitParams'}, StubPropertySource {name='servletContextInitParams'}, PropertiesPropertySource {name='systemProperties'}, OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}, RandomValuePropertySource {name='random'}, OriginTrackedMapPropertySource {name='Config resource 'classpath resource [application.properties]' via location 'optional:classpath:/''}]

So the reason why it does not work in this case is that none of the above PropertySource has test.enable, that is, the TestProperties is not refreshed, or it is refreshed after the class is automatically configured.

@ ConditionalOnProperty skip logic

This paper mainly explains the logical relationship between @ ConditionalOnPropert and bean being refreshed, which is implemented in the ConditionEvaluator class.

Public boolean shouldSkip (@ Nullable AnnotatedTypeMetadata metadata, @ Nullable ConfigurationPhase phase) {/ / 1. If there is no Conditional comment, the current bean / / 2 will not be skipped during scanning, and the conditions will be traversed to determine whether it is satisfied.

Therefore, for the comments on the automatic configuration class, Conditional is the premise of whether the current class is allowed to be refreshed. Only if the Conditional condition is met will the current automatic configuration class be added to the bean list to be refreshed. If the Conditional is not satisfied, the bean will be skipped directly, will not be put into the BeandefinitonMap, and there will be no subsequent refresh action.

The timing of @ ConditionalOnProperty is earlier than that of @ EnableConfigurationProperties before BeanDefiniton is created, which explains why test.enable=true and AutoTestConfiguration in TestProperties will not be refreshed.

After reading this article, I believe you have a certain understanding of "SpringBoot automatic configuration failure". If you want to know more about it, you are welcome to follow the industry information channel. Thank you for your reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report