How to enable specific cache names and disable other name using Caffeine cache in Spring boot application - spring

I am using Spring Boot for my application. Using #EnableCaching annotation at application level.
Consider I have multiple cache names like below in some methods on the application
#Cacheable(value = "cache1")
#Cacheable(value = "cache2")
#Cacheable(value = "cache3")
#Cacheable(value = "cache4")
#Cacheable(value = "cache5")
My aim to cache only cache1 for now. So defined following in application.properties
spring.cache.cache-names=cache1
spring.cache.caffeine.spec=maximumSize=100,expireAfterAccess=300s
But when I use the application, I get error like below as it can't find "cache2"
Cannot find cache named 'cache2' for Builder....
I have used multiple cache names in the application. Currently I want to use only cache1 for now. Is it possible to say support only these cache names via some property? How to accomplish it?

Related

Alternative way for setting default for #Value-annotated field in Spring Boot

I have a Spring Boot application written in Kotlin and I would prefer to set the default of a #Value-annotated field like below:
#Value("\${service-clients.logging.exceptions:/}")
private var loggingExceptions: Array<String> = emptyArray()
Is there anything wrong with doing it this way? Most of the resources I found on the web recommend to set the default in the annotation itself. Is there any advantage of doing it that way?

Redis cache metrics with Prometheus(Spring boot)

I am using RedisTemplate for caching purpose in my spring boot service. Now I want to check cache hit/cache miss through end point actuator/prometheus. But can not see cache hit/cache miss for the cache.
The code I have written is something like below
#EnableCaching
#Configuration
public class CachingConfiguration {
#Bean
public RedisTemplate<String, SomeData> redisTemplate(LettuceConnectionFactory connectionFactory, ObjectMapper objectMapper)
{
RedisTemplate<String, SomeData> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
var valueSerializer = new Jackson2JsonRedisSerializer<SomeData>(SomeData.class);
valueSerializer.setObjectMapper(objectMapper);
template.setValueSerializer(valueSerializer);
return template;
}
}
Now am doing like below to get and save into cache
to get:-
redisTemplate.opsForValue().get(key);
And to save:-
redisTemplate.opsForValue().set(key, obj, some_time_limit);
My cache is working properly, am getting able to save into cache and getting proper data.
But I don't see cache hit/miss related data inside actuator/prometheus.
In my application.yml file I have added below
cache:
redis:
enable-statistics: 'true'
I would assume that in order for Springboot Cache Monitoring to apply (Including Hits/Misses), you would need to depend on AutoConfiguration.
In your case you are creating the RedisTemplate yourself, and probably enable-statistics is not actually applied.
Can you remove the redistemplate creation and use #Cacheable annotation abstraction? That way any supported Cache library will work out of the box, without you having to create #Bean and manually configuring it.
Otherwise, generally if you wanted to enable statistics on a cache manager manually, you will need to call RedisCacheManager.RedisCacheManagerBuilder enableStatistics():
https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/cache/RedisCacheManager.RedisCacheManagerBuilder.html
For Reference:
Auto-configuration enables the instrumentation of all available Cache
instances on startup, with metrics prefixed with cache. Cache
instrumentation is standardized for a basic set of metrics.
Additional, cache-specific metrics are also available.
Metrics are tagged by the name of the cache and by the name of the
CacheManager, which is derived from the bean name.
Only caches that are configured on startup are bound to the registry. For caches not
defined in the cache’s configuration, such as caches created on the
fly or programmatically after the startup phase, an explicit
registration is required. A CacheMetricsRegistrar bean is made
available to make that process easier.
I had exactly the same question and spent a good number of hours trying to figure out how to enable cache metrics for my manually created RedisTemplate instance.
What I eventually realised is that it's only RedisCache class which collects and exposes CacheStatistics through getStatistics() method. As far as I can see there is nothing like that for RedisTemplate, which means you either need to switch to using RedisCache through RedisCacheManager and #Cacheable annotation or implement your custom metrics collection.

Spring boot application properties load process change programatically to improve security

I have spring boot micro-service with database credentials define in the application properties.
spring.datasource.url=<<url>>
spring.datasource.username=<<username>>
spring.datasource.password=<<password>>
We do not use spring data source to create the connection manually. Only Spring create the database connection with JPA.(org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration)
We only provide the application properties, but spring create the connections automatically to use with the database connection pool.
Our requirement to enhance the security without using db properties in clear text. Two possible methods.
Encrypt the database credentials
Use the AWS secret manager. (then get the credential with the application load)
For the option1, jasypt can be used, since we are just providing the properties only and do not want to create the data source manually, how to do to understand by the spring framework is the problem. If better I can get some working sample or methods.
Regarding the option-2,
first we need to define secretName.
use the secertName and get the database credentials from AWS secret manager.
update the application.properties programatically to understand by spring framework. (I need to know this step)
I need to use either option1 and option2. Mentioned the issues with each option.
What you could do is use environment variables for your properties. You can use them like this:
spring.datasource.url=${SECRET_URL}
You could then retrieve these and start your Spring process using a ProcessBuilder. (Or set the variables any other way)
I have found the solution for my problem.
We need to define org.springframework.context.ApplicationListenerin spring.factories file. It should define the required application context listener like below.
org.springframework.context.ApplicationListener=com.sample.PropsLoader
PropsLoader class is like this.
public class PropsLoader implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
#Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
String appEnv = environment.getProperty("application.env");
//set new properties based on the application environment.
// calling other methods and depends on the enviornment and get the required value set
Properties props = new Properties();
props.put("new_property", "value");
environment.getPropertySources().addFirst(new PropertiesPropertySource("props", props));
}
}
spring.factories file should define under the resources package and META-INF
folder.
This will set the application context with new properties before loading any other beans.

Spring Boot Custom Properties - How to include externalize properties when class is not in the application context

It is hard to understand but for my application a required format. I have some custom libraries which are included at runtime and so they are not in the spring application context. To get apis from spring boot application I catched required apis and overhand this to my external classes.
To show an example:
HashValueService hashValueService
= (HashValueService) appContext.getBean("hashValueServiceImpl");
ServiceList srvList = new ServiceList();
srvList.setHashValueService(hashValueService);
In this way I'm able to get access to my database, which is in my application context.
I have a lot of properties distributed in the whole application. So I want to use the default application.properties to centralized often used properties in my application, like the keystore.
For that I edited application.properties with this line:
application.keystore=server.jks
But of course the usage of the Spring's #Value does show me a null for that attribute, because this class is not in my application context:
#Value("${application.keystore}")
private String keystore;
Do you have an idea to overhand this properties to this customer libraries? Maybe the creation of a new property file whould help? Thank u a lot.
Majority of Spring magic is done by BeanPostProcessors. Take a good look at them - link.
#Value wiring (and much more) is performed by AutowiredAnnotationBeanPostProcessor, you can use it for your purpose:
AutowiredAnnotationBeanPostProcessor beanPostProcessor =
appContext.getBean(AutowiredAnnotationBeanPostProcessor.class);
ServiceList srvList = new ServiceList();
beanPostProcessor.processInjection(srvList);
After that, your ServiceList should have String keystore field initialized.

How to Cache HTTP Requests made with Netflix's Feign library in a Java Spring app

In a spring boot application using Netflix's Feign to make HTTP requests to a service, is there an easy way to cache and return these cached values automatically? The cache should be based on the parameters passed to the request (similar to memoizing a function for X minutes).
I'm looking for something like the #Cache annotation below:
#Component
#FeignClient(value = "facebook", url = "${auth.facebook.url}")
public interface FacebookClient {
#Cache(600) // Something like this.
#RequestMapping(method = RequestMethod.GET, value = "/debug_token?input_token={input_token}&access_token={access_token}")
Map debugToken(#PathVariable("input_token") String inputToken, #PathVariable("access_token") String appToken);
}
Of course I could cache it myself using a decorator around the FacebookClient, I was wondering if there was a quicker/less code way.
Springs #Cacheable does what you need.
Check: Caching Data with Spring
Feign does not support caching. I would prefer the JCache (JSR-107) and maybe use it via the spring-boot-starter-cache described in the spring guide
JCache is an abstraction for the proprietary implementation of EhCache, Hazelcast, ... so it is possible to change the implementation with very less impact on the application. At first I would prefer EhCache 3.
Feign client doesn't support caching.
Another better way would be to create a Service class which calls FeignClient and put up cache on methods of this new Service class.

Resources