Spring boot 1.x , How to increment a metric by an amount - java

I have an application built with spring boot 1.x and the whole process to expose metric is different from v2.x of spring boot.
Currently, I am using a cache in my application where i check for key existence in bulk and my requirement is that the counterService that increments a metric should increment it by some amount rather than by 1 so that I can leverage the bulk part atleast.
How do i achieve that?
One way i have done before is including Dropwizard metrics in spring boot. But I want to work under the scope of Spring boot actuators.

You may just have to implement your own CounterService using the DefaultCounterService as a template: https://github.com/spring-projects/spring-boot/blob/v1.5.17.RELEASE/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/writer/DefaultCounterService.java
Then add methods something to the tune of increment(String metricName, int delta).
Then register an instance of the bean in your configuration - and it'll override the DefaultCounterService.
You'll need to refer to the instance by your specific type name so you can access the methods you added.

Related

How to test inmemory caching using Caffeine cache manager? (i.e. getting the count of entries in cache after caching, cache evict)

I want to get the details of entries in my custom cache after caching data or eviction of data.
I tried using actuator dependency to get 'actuator/metrics' path to get details but I'm getting empty tomcat server cache. There is no sign of my custom cache say myCache (the name which I passed into #Cacheable annotation value argument).
You tagged your question with Caffeine and Spring Boot, so I assume you use those two products.
If you use a recent Spring Boot and Caffeine, statistics will be automatically available at actuator/caches. If not, double check you have the needed libraries on your classpath and no configuration that enables another cache or disables caching at all, like spring.cache.type=none.
If you don't use Spring Boot, but just Spring, you need to add a CacheManager to your configuration, otherwise Spring defaults to the ConcurrentHashMap which does not have cache statistics.

How to avoid putting #RefreshScope on multiple beans in my application

We are externalizing configuration of our microservices (spring boot based) using spring cloud.
As per my understanding on Spring Cloud, to enable the beans loading refreshed/updated values from Config server we need to do 2 things in Spring Cloud Client:
add #RefreshScope on the beans reading values from property files
using #Value
add spring actuator to provide /refresh endpoint to
refresh the context.
Scenario:
We have 100s of classes reading values from property file using #Value.
I have to mark all these beans refresh enabled using #RefreshScope annotation.
How can I avoid putting #RefreshScope annotation on all these classes.
Is there any shortcut or spring cloud feature to get around this situation.
You may want to look into Spring Boot feature called #ConfigurationProperties. It is designed to better organize several external configuration options.
According this Github issue, it should work for spring-cloud without #RefreshScope usage.
EDIT (reaction on comment): Maybe you are missing point of #ConfigurationProperties. With this annotation, you wouldn't use it in other configuration classes. You would have dedicated class (or few classes) only for reading and providing properties. Other configuration classes would inject this configuration holder bean.
You could encapsulate your #Values into one (or several) ConfigurationService bean which is #RefreshScoped and autowire this service into your classes instead. That way you only have a small amount of request scoped beans and your services can stay singletons.

how to set kafka consumer concurrency using spring boot

I am writing a Java based Kafka Consumer application. I am utilizing kafka-clients, Spring Kafka and Spring boot for my application. While Spring boot lets me easily write Kafka Consumers (without really writing the ConcurrentKafkaListenerContainerFactory, ConsumerFactory etc), I want to be able to define / customize some of the properties for these consumers. However, I could not find out an easy way to do it using Spring boot. For eg: some of the properties that I would be interested in setting up are -
ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG
ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG
I took a look at the Spring Boot pre-defined properties here.
Also, based on an earlier question here, I want to setup the concurrency on the consumers, but cannot find a configuration, application.properties driven way to do that using Spring Boot.
An obvious way is to define the ConcurrentKafkaListenerContainerFactory, ConsumerFactory classes again in my Spring Context and work from there. I wanted to understand if there is a cleaner way of doing that, especially since I am using Spring Boot.
Versions-
kafka-clients - 0.10.0.0-SASL
spring-kafka - 1.1.0.RELEASE
spring boot - 1.5.10.RELEASE
At the URL you cited, scroll down to
spring.kafka.listener.concurrency= # Number of threads to run in the listener containers.
spring-kafka - 1.1.0.RELEASE
I recommend upgrading to at least 1.3.5; it has a much simpler threading model, thanks to KIP-62.
EDIT
With Boot 2.0, you can set arbitrary producer, consumer, admin, common properties, as described in the boot documentation.
spring.kafka.consumer.properties.heartbeat.interval.ms
With Boot 1.5 there is only spring.kafka.properties as described here.
This sets the properties for both producers and consumers, but you may see some noise in the log about unused/unsupported properties for the producer.
Alternatively, you can simply override Boot's consumer factory and add properties as needed...
#Bean
public ConsumerFactory<?, ?> kafkaConsumerFactory(KafkaProperties properties) {
Map<String, Object> consumerProps = properties.buildConsumerProperties();
consumerProps.put(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG, 5_000);
return new DefaultKafkaConsumerFactory<Object, Object>(consumerProps);
}
I googled for it and found https://github.com/spring-projects/spring-kafka/issues/604. The issue had been closed citing https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#boot-features-kafka-extra-props. But is for spring boot version 2.0.

Ease of rolling back from Spring Boot to regular Spring and viewing hybrid of Spring Context and configurations while using Spring Boot

I am assessing whether spring-boot and how I could migrate to using it.
One question I have is whether a project that uses spring boot can be converted easily back to a regular spring project which uses the traditional spring configuration files if that is required. This would be useful in my mind for a few reasons.
1) merging with legacy projects, because as I have read moving from legacy spring to spring-boot is somewhat tedious.
2) Obtaining a view of the spring application context file and webapp configuration files to understand what the actual configurations being used are.
Another question I have is regarding the lack of application-context file, is there a way to have some kind of hybrid where there is still an application-context file that can be seen? Part of my concern is that spring-boot auto configures components without us knowing and learning how they are configured and work together.
Spring Boot provides auto-configuration.
When #SpringBootApplication is encountered, it triggers a search of the CLASSPATH for a file called META-INF/spring.factories which is just a regular text file that enumerates a list of Java configuration classes. Java configuration was introduced in 2006 and then merged into Spring 3 in 2009. So it's been around for a long time. These Java configuration classes define beans in the same way that XML does. Each class is annotated with #Configuration and therein you find beans defined using methods (factory methods, or provider methods) whose return value is managed and exposed via Spring. Each such provider method is annotated with #Bean. This tells Spring to consider the method and its return value the definition of the bean.
Spring Boot tries to launch all the Java configurations it sees enumerated in that text file. It tries to launch RabbitAutoConfiguration.class, which in turn provides beans for connecting to RabbitMQ and so on. Of course, you don't want those beans in certain cases, so Spring Boot takes advantage of Spring framework 4's #Conditional mechanism to conditionally register those beans only if certain conditions are met: is a type on the CLASSPATH, is a property exposed through the environment, has there been another bean of the same type defined by the user, etc. Spring boot uses these to only create the RabbitMQ-specific beans if, for example, the dependencies that you would get from org.springframework.boot:spring-boot-starter-amqp are on the CLASSPATH. It also considers that the user may have provided a different implementation of RabbitTemplate in some othe rbean definition (be it XML or Java configuration) so it uses that if it's there.
These java configuration classes are the same sort of Java configuration classes you would write without Spring Boot. BUT... WHY? 80% of the time, the auto-configuration that Spring Boot provides is going to be as good or better than the configuration you would write yourself. There are only so many ways to configure Spring MVC, Spring Data, Spring Batch, etc., and the wager you take using Spring Boot is that the leaders and engineers on those various projects can provide the most sensible 80%-case configuration that you probably don't care to write, anyway.
So, yes you could use Spring Boot with existing applications, but you'd have to move those existing applications to Spring 4 (which is easy to do if you're using the spring-boot-starter-* dependencies) to take advantage of #Conditional. Spring Boot prefers: NO configuration, Java configuration, XML configuration, in that order.
If you have an existing application, I'd do the following:
find out what dependencies you can remove from your Gradle/Maven build and just have taken care of for you with the various spring-boot-starter- dependencies.
add #SpringBootApplication to a root component class. Eg, if your package is a.b.c, put a class Application in a.Application and annotate that with #SpringBootApplication
You can run it as a Servlet 3 application or in an embedded servlet container. It might be easier to just run in a standard servlet container as you take baby steps. Go to http://start.spring.io and make sure to choose war in the packaging drop down. Copy the ServletInitializer class and the specification from the pom.xml to ensure that your application is a .war, not a .jar. Then, once everything works on Spring Boot, rm -rf the Initializer and then revert the Maven build to a simpler .jar using the Spring Boot plugin for extra win.
If your application has lots of existing configuration, import it using #Import(OldConfig.class) or #ImportResource("old-config.xml") on the a.Application configuration class. The auto-configuration will kick in but it will see, for example, that you may have already defined a DataSource so it'll plug that in in the right places. What I like to do now is just start the application up, see if everything's OK, then start removing code in my old Java or XML configuration. Don't remove your business code, but remove things related to turning on parts of Spring. Anything that looks like #Enable..* or ..:annotation-driven/>. Restart and verify things still work. The goal is to let Spring Boot do as much of the heavy lifting as possible. Viewing the source is very handy here so you can see what Spring Boot will try to do for you. Spring Boot will log information on what #Conditional conditions evaluated to true for you. Simply provide --Ddebug=true wen you start the application to see the output. You could also export DEBUG=true then restart your IDE to run it as long as the environment variable is ivsible in your shell.

How does the EnableAutoConfiguration spring annotation work?

I am no fan of gross over abstractions, And i think Spring has committed a major felony.
But I'm willing to overlook it this time if someone can explain the algorithm behind the 'auto' configuration.
Having a look at spring's own javadocs, It doesn't give much away other than saying that it will intelligently guess what you need and something to do about conditional beans.
Does someone know what algorithm is used to determine what needs to be loaded?
In my experience as a Spring Boot user the basic factors for Spring Boot to decide on what auto-configurations will be enabled are:
1) The classes present on the classpath. For example if RabbitMQ and Spring AMQP classes are present, then the RabbitAutoConfiguration will be enabled. The corresponding annotation is #ConditionalOnClass,
2) The presence or not of user defined beans. For example, if all the Spring Data JPA is present on the classpath, Spring Boot will register a LocalContainerEntityManagerFactoryBean bean only if the user has not already done so. The beans registered by the user will 'override' the default ones. The relevant annotation is #ConditionalOnMissingBean
As #DaveSyer mentions, you can of course use Spring Boot without #EnableAutoConfiguration if you want to include the relevant configuration on your own. Or you could use the less drastic solution of the exclude field of #EnableAutoConfiguration. If for example you want Spring Boot to autoconfigure everything except ActiveMQ, you would use #EnableAutoConfiguration(exclude=ActiveMQAutoConfiguration.class)
In my opinion, there is absolutely no felony here! You can use what you want from Spring Boot. When you don't want something it has to offer, you can easily opt out partially or completely!
Also if you want to get a look under the covers, you can add the property
logging.level.org.springframework.boot=DEBUG
to application.properties and Spring Boot will gladly give a detailed report of what was auto-configured and what wasn't
There is some documentation in the Spring Boot Reference Guide. It's not terribly complicated, and I hardly think it's a felony to just include a bunch of #Configuration that you might have written anyway (because that's all it does). Feel free not to use #EnableAutoConfiguration if you prefer to include the individual configurations individually.

Categories