I am looking for help involving a spring application ( someone else's design ) that uses kafka consumers and producers.
The design allows for a config.properties file that contains an entry like so:
kafkaAddress=10.10.10.12:9093,10.10.10.11:9093,10.10.10.10:9093
Such config is picked up by some kind of spring bean code like this...
Java code...
private String kafkaAddress;
public String getKafkaAddress() {
return kafkaAddress;
}
public void setKafkaAddress(String kafkaAddress) {
this.kafkaAddress = kafkaAddress;
}
And it shows up in a Properties object I see with debugger.
"kafkaAddress" -> "10.10.10.12:9093,10.10.10.11:9093,10.10.10.10:9093"
The code passes the Properties object to constructor of the Kafka client
I thought this all happened through the design of spring and matching config "kafkaAddress" with a String of matching name kafkaAddress
Well I want to config for ssl such things as ...
ssl.truststore.location=C:\some\path\kafka.client.10.10.10.11.truststore.jks
ssl.truststore.password=mySecretWord
I put such things in config but what do i put for my setter and getter?
I can't put String ssl.truststore.location, right?
In config.properties I use ...
ssl_truststore_password=mySecretPassword
In setters and getters in MyConsumerConfig.java file I use...
public void setSsl_truststore_password(String ssl_truststore_password ) {
this.ssl_truststore_password = ssl_truststore_password;
}
public String getSsl_truststore_password() {
return this.ssl_truststore_password;
}
Before call to constructor .java file I ...
if(StringUtils.isNotEmpty(myConsumerConfig.getSsl_truststore_password())) {
consumerProps.put(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG,
onlineConsumerConfig.getSsl_truststore_password());
}
The SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG is defined in package org.apache.kafka.common.config.SslConfigs ...
public static final String SSL_TRUSTSTORE_PASSWORD_CONFIG "ssl.truststore.password"
The spring framework links the "ssl_truststore_password" in the config file to the getters and setters such as ...
MyConsumerConfig.setSsl_truststore_password(String ssl_truststore_password)
Related
I have a spring-boot application where I read data from queue and send data to transformation class using .bean()
Integration.java
class Integration {
#Value("${someURL}")
private String someURL; //able to read someURL from property file
from("queue")
// some intermediate code
.bean(new TransformationClass(), "transformationMethod")
// other code
}
Now, Inside TransformationClass I have #Value annotation to read values from properties file but it always returns a null.
TransformationClass.java
#Component
class TransformationClass {
#Value("${someURL}")
private String someURL; //someURL return null though there is key-value associated in props file.
public void transformationMethod(Exchange exchange) {
// other stuff related to someURL
}
}
Note - I am able to read values from property file in class Integration.java but unable to read from class TransformationClass.java
I am using spring boot version - 2.7.2 and camel version - 3.18.1 jdk - 17
I tried to read using camel PropertiesComponent but it did not worked.
Problem here is, that new TransformationClass() is not a "spring managed instance", thus all #Autowire/Value/Inject/...s have no effect.
Since TransformationClass is (singleton, spring-managed) #Component and is needed by Integration, wiring these makes sense:
Via field... :
class Integration {
#Autowired
private TransformationClass trnsObject;
// ...
Or constructor injection:
class Integration {
private final TransformationClass trnsObject;
public Integration(/*im- /explicitely #Autowired*/ TransformationClass pTrnsObject) {
trnsObject = pTrnsObject;
}
// ...
// then:
doSomethingWith(trnsObject); // has correct #Values
}
Is it possible to have a Spring Boot properties file depend on two or more profiles? Something like application-profile1-profile2.properties?
Spring Boot does not support this out of the box. It only supports a single profile as described here.
However, it does provide enough flexibility to add your own property sources using EnvironmentPostProcessor.
Here is an example of how to implement this:
public class MultiProfileEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
private final ResourceLoader resourceLoader = new DefaultResourceLoader();
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
String[] activeProfiles = environment.getActiveProfiles();
for (int i = 2; i <= activeProfiles.length; i++) {
Generator.combination(activeProfiles).simple(i)
.forEach(profileCombination -> {
String propertySourceName = String.join("-", profileCombination);
String location = "classpath:/application-" + propertySourceName + ".properties";
if (resourceLoader.getResource(location).exists()) {
try {
environment.getPropertySources().addFirst(new ResourcePropertySource(propertySourceName, location));
} catch (IOException e) {
throw new RuntimeException("could not add property source '" + propertySourceName + "'", e);
}
}
});
}
}
#Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
Couple of things to note:
This implementation only supports .properties files but can easily be extended to .yml files as well.
getActiveProfiles already returns the profiles in an order where the last one wins. This implementation relies on this order and builds the different file names leveraging this order. i.e. if active profiles are: profile1,profile2,profile3 then application-profile1-profile3.properties is supported but application-profile3-profile1.properties isn't, and application-profile1-profile3.properties will override properties defined in application-profile1.properties or application-profile3.properties.
This implementation uses a third party library com.github.dpaukov:combinatoricslib3 to create the different sets of profiles.
The property sources are added to the front of the property source list to override existing sources. But if you have custom property sources that should take precedence you need to modify this a bit to consider them in the order, i.e. by leveraging methods like Environment.addAfter.
Registering an EnvironmentPostProcessor is done using the spring.factories file.
There are 4 ways I know.
insert .yaml or .properties programmatically like Asi Bross Said. Use ResourceLoader or YamlPropertySourceLoader to insert.
Use .yaml. but it will be replace when you have a another spring project to dependent it.
Use properties instead of profiles. (For api project)
Use one #PropertySource to define properties file A.
Get the variables from properties file A and assign them to the parameters in another #PropertySource file path expression.
For example:
resources
/-application.properties <-- remove or empty,because it will be override by application project
/-moduleA
/-application.properties <-- Intellij can identify properties files started with application-
/-application-mysql-dev.properties
/-application-psql-dev.properties
/-application-psql-prod.properties
The content of resources/moduleA/application.properties :
moduleA.custom.profile1=mysql
moduleA.custom.profile2=dev
Content of Java Config file:
#SpringBootApplication
#PropertySources({
#PropertySource("/moduleA/application.properties"),
#PropertySource("/moduleA/application-${moduleA.custom.profile1}-${moduleA.custom.profile2}.properties"),
})
public class ModuleConfig {}
Use properties instead of profiles. (For application project)
resources
/-application.properties
/-application-mysql-dev.properties
/-application-psql-dev.properties
/-application-psql-prod.properties
The content of resources/application.properties :
moduleA.custom.profile1=mysql
moduleA.custom.profile2=dev
The content of SpringMvcApplication.java:
#SpringBootApplication
#PropertySource("/application-${moduleA.custom.profile1}-${moduleA.custom.profile2}.properties")
public class SpringMvcApplication {...}
I have written queries in property file. I want to read the property file in to one class with annotations in spring boot. How can i read it? And is there any better approach for writing queries in spring boot project?
If you add your properties in application.properties file, you can read them inside the spring boot classes like:
#Service
public class TwitterService {
private final String consumerKey;
private final String consumerKeySecret;
#Autowired
public TwitterService(#Value("${spring.social.twitter.appId}") String consumerKey, #Value("${spring.social.twitter.appSecret}") String consumerKeySecret) {
this.consumerKey = consumerKey;
this.consumerKeySecret = consumerKeySecret;
} ...
You can annotate fields in your components by #Value("${property.name}")
Else, you can use Properties Object in java.util package.
For example, i have a mode property, which values are dev or prod, i can use it in my beans as follow :
#Value("${mode:dev}")
private String mode;
The other approach is by using :
Properties pro = new Properties();
pro.load(this.getClass().getClassLoader().getResourceAsStream());
You can use #PropertySource to read the properties from a file and then pass them to a bean. If you have a file called "queries.properties" that has a property like:
query1: select 1 from foo
Then your config might look like:
#PropertySource("classpath:queries.properties")
#Configuration
public class MyConfig {
#Bean
public DbBean dbBean(#Value("${queries.query1}") String query) {
return new DbBean(query);
}
}
I've defined an application name using the bootstrap.yml file in my spring boot application.
spring:
application:
name: abc
How can i get this application name during runtime/programmatically ?
You should be able to use the #Value annotation to access any property you set in a properties/YAML file:
#Value("${spring.application.name}")
private String appName;
#Autowired
private ApplicationContext applicationContext;
...
this.applicationContext.getId();
Please, find this:
# IDENTITY (ContextIdApplicationContextInitializer)
spring.application.name=
spring.application.index=
In Spring Boot Reference Manual.
And follow with source code for that ContextIdApplicationContextInitializer class:
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.setId(getApplicationId(applicationContext.getEnvironment()));
}
Where the default behavior is with this:
/**
* Placeholder pattern to resolve for application name
*/
private static final String NAME_PATTERN = "${vcap.application.name:${spring.application.name:${spring.config.name:application}}}";
Since the #Value annotation is discouraged in Spring Boot when referencing configuration properties, and because applicationContext.getId(); doesn't always return the value of spring.application.name another way is to get the value from the Environment directly
private final Environment environment;
...
public MyBean(final Environment environment) {
this.environment = environment;
}
...
private getApplicationName() {
return this.environment.get("spring.application.name");
}
Another possible way would be to create your own ConfigurationProperties class to get access to the value.
I'm not saying these are the best ways, and I hope/wish that there is a better way, but it is a way.
Note! If your using a SpringBootTest, you need to suplly the properties/yml.
Otherwise, the environment/appcontext does not load the config files.
The, your app name is not set.
Like so:
#PropertySource("classpath:application.properties")
#RunWith(SpringRunner.class)
#SpringBootTest
....
This post is aged but I hate unanswered questions.
So use the following snippet:
#Value("${spring.application.name [: defaultValue]}")
private String appName;
What is between [] is optional.
So I found a really ugly way to do this, but it works so I'm not searching further. Maybe this will help someone.
The basic premise is that spring Environment stores the value inside a propertySource.. It appears that bootstrap config is stored in the ResourcePropertySource and so you can get it from that. For me it is currently throwing an exception, but then I can get the value out of the exception, so I haven't looked any further:
try {
this.environment.getProperty("name", ResourcePropertySource.class);
} catch (ConversionFailedException e) {
String res = (String)e.getValue();
}
And then you can just do this for every property you are interested in.
Like I said ugly, but it works.
I have an Xtext project, and i would like to use an external properties file to be used in validation..
e.g. for the Hello world! project, and the following properties file...
hello.properties:
name=world
...create a validation rule that checks for Hello world! that world is the value of name in the properties file.
I would like the properties to only be read in once, such as when eclipse loads rather than every time the validation method is run as I am guessing this will be very slow. Where can I read them in so that this is the case?
Thanks, Sean
You may want to provide a class that allows to retrieve the values from the properties file. This class should be marked as #Singleton and clients of that implementation have to obtain the only instance via dependency injection.
#Singleton
public class MyPropertiesAccess {
private Properties properties;
public Properties getProperties() {
if (properties == null) {
properties = ...load...
}
return properties;
}
}
public class MyDslValidator {
#Inkect MyPropertiesAccess propertiesAccess;
}