A Spring Boot 1.5.1 (non-web) application was written to extract database rows. Tomcat datasource is auto configured because it is included in the pom.xml i.e.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>${spring-boot.version}</version>
</dependency>
Therefore, these keys are required,
spring.datasource.driver-class-name=${db.driver}
spring.datasource.url=${db.url}
spring.datasource.username=${db.username}
spring.datasource.password=${db.password}
and when any of these variables, e.g. ${db.driver} or ${db.url}, is missing, the application would dump the whole error stack.
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'db.driver' in string value "${db.driver}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:236)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210)
...
This made fixing simple problems difficult because lots of text were churned and cluttered the actual problems.
How do I make Spring Boot report custom simple error messages defined by me when, say, ${db.driver} or any of the variables is not defined anywhere in, for example, application.properties or JVM environment? Thanks
Update 1
I given some thoughts after the 1st comment. I am not so much as to look to change the exception messages nor prevent them from thrown out into the log. I want to check or intercept the required parameters before they are passed to the actual module to access. Case in point, the data source.
If you supply a default value, non existing placeholders will not lead to an exception. Instead the default value is used.
You could set the default for the properties in the properties file where you use them
spring.datasource.url=${db.url?localhost:123//whatever}
You can than check the properties in a #PostConstruct annotated method or an ApplicationListener and report the error however you want.
But this does not make too much sense, because when spring tries to create a connection to the database it will fail without correct configuration.
Depending on your application, this may already happen during application startup.
Related
I'm currently working on a spring webflux project using Spring cloud sleuth dependency.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<version>2.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.5.1</version>
</dependency>
I'm working on a set of APIs which get a request payload that contains 3 Strings. I want to concatenate these 3 strings to use as my custom trace id. I also want to achieve the following requirement.
This custom_trace_id should be able to be added to every log. (We are getting sleuth trace id in logs by adding %X{traceId} within our log4j.xml file to print the traceId in all logs)
This custom trace id must be sent to the calls that are made by WebClient (Sleuth sets the X-B3-TraceId header to all calls made by WebClient, I want the same but using the custom_trace_id)
If possible I want to change the name of X-B3-TraceId header to a different value such as correlation-id so that if someone makes a request to our spring webflux application the sleuth should first check the correlation-id and use it as trace id. (Note: custom_trace_id = correlation-id)
Note that the spring sleuth already does the above 3 things. I want to have custom value for the trace id instead. Can someone please help or suggest something for my usecase
Spring Boot 2.5.x is not compatible with Spring Cloud Hoxton (Sleuth 2.2.x).
You need to use Spring Cloud 2020.0.x aka Ilford (Sleuth 3.0.x).
You can set spring.sleuth.propagation.type to CUSTOM and implement your own Propagation and Propagation.Factory, please see the docs: How to Change The Context Propagation Mechanism?.
This should help you achieving your goals above, however, there are some downsides. This is mostly my opinion, please feel free to ignore it and do whatever you would like to:
B3, W3C and AWS propagation types are standards with support of other projects/tooling
You are trying to create a 4th "standard" that is not supported by anything (but maybe by an internal system)
You need to add support for this custom propagation type to every new component so that they will also understand this "standard"
Sometimes it worth consider moving to a universal standard rather than using a custom one even if there is a legacy system behind it
I need to fetch a property with the following format:
${/a/env/mode}
However this depends on where im deployed, I have all the required information in configuration already and is trying to use the following:
${/a/${env}/${mode}}
This is not working as expected in Spring Boot but instead gives an exception. Is there anyway to get what I need?
I am trying to disable Redis when I am testing with spring boot. I have disabled my configuration but the auto config created a default connection and fails because it can't connect to a non-existent service. For testing I am content to just use a basic in-memory cache or a no-op cache. That doesn't work either. Here is what I have tried:
per this issue I added said configuration to my test app properties
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
But. That gets me a bit further. But ultimately I get a NoSuchBeanDefinitionException redisTemplate - this is because redisReferenceResolver is trying to look that up.
Looking at my debugger right now, the bean it's trying to hydrate is:
org.springframework.data.redis.core.convert.ReferenceResolverImpl which is coming from spring-data-redis:1.8.0.RELEASE which is coming from this dependency: compile('org.springframework.boot:spring-boot-starter-data-redis') . I admit, the bean name is a bit misleading. The type it actually resolves to is not
The only other reference to redis is in our hibernate support.
Can someone explain how to turn this off for testing?
Try excluding this two auto-configuration classes in your test properties file:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
or
exclude
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
and set: spring.data.redis.repositories.enabled=false
With YAML syntax (& Spring Boot):
spring.autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
- org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
If you have SystemEnvironmentPropertySource in you app context you can use environment variable SPRING_AUTOCONFIGURE_EXCLUDE separating items with comma:
SPRING_AUTOCONFIGURE_EXCLUDE=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
Also try #EnableAutoConfiguration(exclude = {...}) on a #TestConfiguration annotated class.
If you dont want to change any files/code, you can also do this with an environment variable:
SPRING_AUTOCONFIGURE_EXCLUDE=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
I am trying to figure out how can I dynamically update/reload externalized configuration in a Spring Boot application without restarting the whole application.
Most of the advice involves reloading ApplicationContext after changing the externalized configuration, but that is equivalent to restarting the entire application, so this is not really all that useful.
Reading through SpringBoot reference documentation, I found a chapter 23.7 Typesafe Configuration Properties.
If I understand it correctly, this allows to define simple POJO classes that will hold your application (externalized) configuration values as attributes.
In theory at least, this scheme could be used to bind beans only once to the required configuration POJO and upon configuration change just update the values in the POJO. Components could easily pick up the changes next time they access getters on the POJO...
However, I have yet not managed to figure out how to enable this type of behavior. Is there some glaringly obvious way to dynamically update components annotated with #ConfigurationProperties when relevant configuration has changed?
It sounds like you're looking for #RefreshScope which is provided by Spring Cloud. From the Spring Cloud documentation:
A Spring #Bean that is marked as #RefreshScope will get special treatment when there is a configuration change. This addresses the problem of stateful beans that only get their configuration injected when they are initialized. For instance if a DataSource has open connections when the database URL is changed via the Environment, we probably want the holders of those connections to be able to complete what they are doing. Then the next time someone borrows a connection from the pool he gets one with the new URL.
I'm facing a problem with Spring dependency injection. I have an application that once deployed checks if it's previously configured, if not then it launches configuration manager and asks the user for db host, port, admin login and pass etc.
Now I can't find a way to inject those configured values. I assume that I would have to use lazy init beans but when i add the annotation #Lazy, Spring is still trying to inject them at the runtime and I'm getting an error since the host and port are not yet configured.
What am I missing :/?
You need a lookup method, a feature accessible only through XML configuration. There is an almost ancient JIRA issue still open on this, still unresolved.
Please do check this comment on the mentioned issue, it describes a workaround that may be an option for you.