How to get spring bean properties - spring

I'm loading all loaded beans that have #Configuration annotation like
Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class)
It return a map of <bean-name, Object>
on each configuration, the bean-configuration will have properties
I want to map all bean's properties to a map of property-name, property-value <String, Object>
I can see those on IDE's debugger tools but don't know how to convert them into a map
Any suggestions?
Thank you in advance

Related

Spring boot Kafka metrics configuration

We have a spring boot microservice using spring-kafka. There are a couple of Kafka listeners and producers and the Kafka related metrics are successfully presented at the actuator endpoint. But when adding another maven dependency with custom metrics, the Kafka related metrics provided by spring boot are removed. I suspect it's related to introducing new MeterRegistry bean, but overriding it with the same bean definition as in NoOpMeterRegistryConfiguration in spring-boot-actuator-autoconfigure module of spring-boot didn't help. I've also tried debugging KafkaMetricsAutoConfiguration, and it looks like all the beans are successfully instantiated. Can somebody with more experience with spring-boot-actuator-autoconfigure help me to understand the default configurations for Kafka related metrics, please?
The spring configuration in the new maven dependency is pretty simple, just ProducerFactory and MeterRegistry beans are defined
#Bean
#Primary
public ProducerFactory<Object, Object> producerFactory(MessageCounter messageCounter) {
Map<String, Object> configs = this.kafkaProperties.buildProducerProperties();
configs.put("interceptor.classes", Collections.singletonList(RecordSuccessfullySentInterceptor.class));
configs.put("message.counter.bean", messageCounter);
DefaultKafkaProducerFactory<Object, Object> producerFactory = new DefaultKafkaProducerFactory(configs);
producerFactory.setTransactionIdPrefix(this.transactionId);
return producerFactory;
}
#Bean
public MeterRegistry meterRegistry() {
return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
}
#Bean({"retryProducerFactory"})
public ProducerFactory<Object, Object> retryProducerFactory(MessageCounter messageCounter) {
Map<String, Object> configs = this.kafkaProperties.buildProducerProperties();
configs.put("interceptor.classes", Collections.singletonList(RecordSuccessfullySentInterceptor.class));
configs.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
configs.put("message.counter.bean", messageCounter);
DefaultKafkaProducerFactory<Object, Object> producerFactory = new DefaultKafkaProducerFactory(configs);
producerFactory.setTransactionIdPrefix(this.transactionId);
return producerFactory;
}
It may be possible some transient dependency is messing up spring boot autoconfiguration for Kafka related metrics though.

Class not able to access bean managed by Spring

I have Spring configuration file where I am defining beans but somehow this bean is not accessible from one of the class in same package, though same beans are accessible from Controller class which was annotated as #Controller. I was thinking may be this class was not managed by Spring but that's not the case.
1) Configuration class
#Bean
public FooConsumer fooConsumer() {
return new FooConsumer();
}
#Bean
public Map<String, ProxyConsumer> appProxyConsumerMap() {
Map<String, ProxyConsumer> proxyConsumer = new HashMap<String, ProxyConsumer>();
proxyConsumer.put(FOO_APP, FooConsumer());
return proxyConsumer;
}
#Bean
public FooEventConsumer fooEventConsumer() {
return new FooEventConsumer();
}
#Bean
public Map<String, FooConsumer> fooConsumerMap(){
Map<String, FooConsumer> fooEventConsumer = new HashMap<String, FooConsumer>();
fooEventConsumer.put(FOO_EVENT, fooEventConsumer());
}
2) Controller class
#Resource
#Qualifier("appProxyConsumerMap")
Map<String, ProxyConsumer> appProxyConsumerMap;
//proxyApp comes as path variable
ProxyConsumer consumer = appProxyConsumerMap.get(proxyApp);
//invoke consumer
boolean consumed = consumer.consumeEvent(eventRequest);
//here consumer is my FooConsumer class, till now all works fine.
3) now in FooConsumer class it tries to access Map bean named fooConsumerMap to get which event to call but somehow it returns null.
#Resource
#Qualifier("fooConsumerMap")
Map<String, FooConsumer> fooConsumerMap;
FooEventConsumer consumer = fooConsumerMap.get(eventType);
//Here fooConsumerMap comes as null in this class, though it comes as object in controller class , please advise.
In your configuration file, construct your FooConsumer bean with the FooConsumerMap bean declared in the same configuration.
You can autowire other beans into a configuration file, but to pull together beans within the file you pass them as constructor arguments.
Note that if you call a Bean annotated method multiple times, you will surprisingly always get the same instance even if the method logic constructs a new instance.
Check documentation at https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html

How to create a second RedisTemplate instance in a Spring Boot application

According to this answer, one RedisTemplate cannot support multiple serializers for values. So I want to create multiple RedisTemplates for different needs, specifically one for string actions and one for object to JSON serializations, to be used in RedisCacheManager. I'm using Spring Boot and the current RedisTemplate is autowired, I'm wondering what's the correct way to declare a second RedisTemplate instance sharing the same Jedis connection factory but has its own serializers?
Tried something like this in two different components,
Component 1 declares,
#Autowired
private RedisTemplate redisTemplate;
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Instance.class));
Component 2 declares,
#Autowired
private StringRedisTemplate stringRedisTemplate;
In this case the two templates actually are the same. Traced into Spring code and found component 1's template got resolved to autoconfigured stringRedisTemplate.
Manually calling RedisTemplate's contructor and then its afterPropertiesSet() won't work either as it complains no connection factory can be found.
I know this request probably is no big difference from defining another bean in a Spring app but not sure with the current Spring-Data-Redis integration what's the best way for me to do. Please help, thanks.
you can follow two ways how to use multiple RedisTemplates within one Spring Boot application:
Named bean injection with #Autowired #Qualifier("beanname") RedisTemplate myTemplate and create the bean with #Bean(name = "beanname").
Type-safe injection by specifying type parameters on RedisTemplate (e.g. #Autowired RedisTemplate<byte[], byte[]> byteTemplate and #Autowired RedisTemplate<String, String> stringTemplate).
Here's the code to create two different:
#Configuration
public class Config {
#Bean
public RedisTemplate<String, String> stringTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, String> stringTemplate = new RedisTemplate<>();
stringTemplate.setConnectionFactory(redisConnectionFactory);
stringTemplate.setDefaultSerializer(new StringRedisSerializer());
return stringTemplate;
}
#Bean
public RedisTemplate<byte[], byte[]> byteTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<byte[], byte[]> byteTemplate = new RedisTemplate<>();
byteTemplate.setConnectionFactory(redisConnectionFactory);
return byteTemplate;
}
}
HTH, Mark

Inject a specific subset of all existing Datasources

I need to be able to deal with a dynamic list of Datasources.
To do that i wrote a #Bean method that returns a map of datasources.
#Bean
#ConfigurationProperties(prefix = "partitioning.shards")
public Map<String, DataSource> datasources() {
Map<String, DataSource> datasources = new HashMap<>();
...
return datasources;
}
i a second step i need to process these datasources in a different class. unfortunately i have another factory-method that also creates Datasources to a different database.
is it possible to only get the Datasources injected that my own method created? i tried to annotate my method with a qualifier but that doesn't seem to work.
i was wrong on multiple fronts:
returning a map of datasources does not add the datasources to my context. it just looked like that because of something else my code did. after adding my beans with seperate #Bean methods the Qualifier annotation worked aggain without a problem.

Spring to load the CSV file as List of Object

In My Spring MVC application
I want to load CSV, like I can load properties file.
#Resource(name = "myProperties")
private Map<String, String> myProperties;
#Bean(name="myProperties")
public static PropertiesFactoryBean mapper() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("user-form-validation-configuration.properties"));
return bean;
}
Currently I am using org.apache.commons.csv
Please let me know, if spring provide any util for csv file.
Thanks
Manu
CSV file is not a Properties file. So you cannot convert it to a Map<String, String>
You should inject the class in org.apache.commons.csv package as a Spring bean and then use it to read in your application. Or you can also try org.springframework.batch.item.file.FlatFileItemReader from Spring Batch

Resources