How to configure Redis caching in Spring Boot? - java

How can I configure Redis caching with Spring Boot. From what I have heard, it's just some changes in the application.properties file, but don't know exactly what.

To use Redis caching in your Spring boot application all you need to do is set these in your application.properties file
spring.cache.type=redis
spring.redis.host=localhost //add host name here
spring.redis.port=6379
Add this dependency in your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Additionally, you have to use the #EnableCaching on your main application class and use the #Cacheable annotation on the methods to use the Cache. That is all is needed to use redis in a Spring boot application. You can use it in any class by autowiring the CacheManager in this case RedisCacheManager.
#Autowired
RedisCacheManager redisCacheManager;

You can mention all the required properties that is hostname, port etc. in the application.properties file and then read from it.
#Configuration
#PropertySource("application.properties")
public class SpringSessionRedisConfiguration {
#Value("${redis.hostname}")
private String redisHostName;
#Value("${redis.port}")
private int redisPort;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(redisHostName);
factory.setPort(redisPort);
factory.setUsePool(true);
return factory;
}
#Bean
RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
return redisTemplate;
}
#Bean
RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate());
return redisCacheManager;
}
}

Related

How to create RedisCacheManager in spring-data 3.0.x

I'm migrating my application from spring boot 1.5.x to 3.0.x. I want to keep jedis but I have a problem with the instantiation of RedisCacheManager.
Now constructor signature is
RedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration)
But before it was:
RedisCacheManager(RedisOperations redisOperations)
I define this bean having only RedisTemplate in scope:
#Bean
public CacheManager cacheManager1(RedisTemplate redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
cacheManager.setDefaultExpiration(300);
HashMap<String, Long> expires = new HashMap<>();
expires.put("DELIVERED_DLR_MESSAGE_PART_COUNT_MAP", new Long(1000));
expires.put("FAILED_DLR_MESSAGE_PART_COUNT_MAP", new Long(1000));
cacheManager.setExpires(expires);
cacheManager.setUsePrefix(true);
return cacheManager;
}
How is it supposed to be created now?

How we can access the same cache between two war files?

I am using #Cacheable of Spring annotation to cache the data and Redis as the cache manager.
I created the cache with name xyx on one war, now I want to access/update/delete the same cache on another war.
Below is the code I have used to create the cache manager
#Bean
public JedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
// Defaults
redisConnectionFactory.setHostName("127.0.0.1");
redisConnectionFactory.setPort(6379);
return redisConnectionFactory;
}
Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory cf) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(cf);
return redisTemplate;
}
#Primary
#Bean(name = "cManager")
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager cm= new RedisCacheManager(redisTemplate);
return cm;
}
Below is the method to cache the data in war 1
#Cacheable(value = "xyz" , cacheManager = "cManager")
public Map<String, Map<String, List<DTO>>> cachingData()
throws CustomException {
//logic
}
As long as both web applications are connecting to the same Redis instance, and using the same cacheName and cache key, this should work transparently, as if it was in the same war.
Example annotation
#Cacheable(cacheNames = "myCache", key = "'myKey'")
public String myCacheableMethod(){
return "some value";
}

How to use Spring Cache Redis with a custom RestTemplate?

I'm migrating my Spring application from Spring-boot 1.5.9 to Spring-boot 2.0.0.
With this new Spring bundle, I have some issues with caching data in Redis.
In my Configuration, I have 3 CacheManager with differents TTL (long, medium and short) :
#Bean(name = "longLifeCacheManager")
public CacheManager longLifeCacheManager() {
RedisCacheConfiguration cacheConfiguration =
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(redisExpirationLong))
.disableCachingNullValues();
return RedisCacheManager.builder(jedisConnectionFactory()).cacheDefaults(cacheConfiguration).build();
}
I also have a custom RestTemplate :
#Bean
public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<?, ?> template = new RedisTemplate<>();
template.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(connectionFactory);
return template;
}
With the previous Spring version, every data that is cached use this RestTemplate and was serialized with the GenericJackson2JsonRedisSerializer.
With the new Spring version, the CacheManager don't use the RestTemplate but use its own SerializationPair. This result to everything beeing serialized with the default JdkSerializationRedisSerializer.
Is it possible to configure the CacheManager to use the RestTemplate and how ?
If it is not possible, what can I do to use the JacksonSerializer instead of the JdkSerializer ?
I finally found a working solution.
I can't configure the CacheManager to use my RedisTemplate, but I can set the Serializer like this :
#Bean(name = "longLifeCacheManager")
public CacheManager longLifeCacheManager(JedisConnectionFactory jedisConnectionFactory) {
RedisCacheConfiguration cacheConfiguration =
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(redisExpirationLong))
.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(jedisConnectionFactory).cacheDefaults(cacheConfiguration).build();
}
The serializeValuesWith method is the key.

spring boot assign specific DataSource to JpaRepository

I have two datasources that I'm trying to assign a specific datasource to each JpaRepositories. I'm using the spring boot framework. The primary datasource is used about 90% of the time while the secondary datasource is used about 10% so it would be nice to default to the primary and only assign the secondary datasource when required. I tried using the docs here https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html , but I dont think its exactly what I need. Any tips would be great!
spring.datasource.configuration.url=jdbc:postgresql://localhost:5432/mydatabase
spring.datasource.configuration.username=dockerusername
spring.datasource.configuration.password=dockerpassword
spring.datasource.configuration.driver-class-name=org.postgresql.Driver
spring.datasource.cached.url=jdbc:hsqldb:mem:main
spring.datasource.cached.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.datasource.initialize=false
spring.jpa.database=default
spring.jpa.hibernate.ddl-auto=update
config file
#Configuration
#ComponentScan({"com.praeses.gov"})
public class Config {
#Bean
#ConfigurationProperties("spring.datasource.configuration")
public DataSourceProperties configDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#ConfigurationProperties("spring.datasource.configuration")
public DataSource configDataSource() {
return configDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.cached")
public DataSourceProperties cachedDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.cached")
public DataSource cachedDataSource() {
return cachedDataSourceProperties().initializeDataSourceBuilder().build();
}
repository that uses the primary datasource
#Qualifier("spring.datasource.cached")
#Repository("spring.datasource.cached")
public interface GeoitemRepository extends JpaRepository<Geoitem, String> {
}
repository that uses the secondary datasource
#Qualifier("spring.datasource.configuration")
#Repository("spring.datasource.configuration")
public interface GeoitemhistoryRepository extends JpaRepository<Geoitemhistory, String> {
}
You can do something on similar lines as below link. Just create two config files instead of one(one each for each datasource) and add both of them to your main application.
Also, in the properties file, give as below:
datasource.local.url=
datasource.local.driver-class-name=
datasource.local.username=
datasource.local.password=
datasource.primary.url=
datasource.primary.driver-class-name=
datasource.primary.username=
datasource.primary.password=
Also, give #Primary annotation to the LocalContainerEntityManagerFactoryBean and platformTransactionManager in the config file for primary datasource.
See this answer for more details:
https://stackoverflow.com/a/44971911/6775742

how can i parameterize datasource properties on Spring 4?

I am using Spring 4.16. I want to parameterize my persistence data. This is my config right now:
#Configuration
#EnableTransactionManagement
public class PersistenceConfiguration {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setDataSource(this.dataSource());
entityManager.setPackagesToScan(new String[] {"com.example.movies.domain"});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManager.setJpaVendorAdapter(vendorAdapter);
entityManager.setJpaProperties(this.properties());
return entityManager;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/sarasa_db");
dataSource.setUsername("root");
dataSource.setPassword("mypassword");
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private Properties properties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.setProperty("hibernate.show_sql", "false");
return properties;
}
}
And i want to parameterize on my application.properties all things i can. First of all, i want to put in datasource properties (so as i was reading, is possible that spring builds my datasource automatically, but apparently that is only using JdbcTemplate...):
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sarasa_db
spring.datasource.username=root
spring.datasource.password=mypassword
And, if it's possible, all the Properties's properties, which i couldn't find nothing in doc
Do you know how could i do it ?
EDIT
This is my DAO implementation
#Configuration
#Import(PersistenceConfiguration.class)
public class DAOConfiguration {
#PersistenceContext
private EntityManager entityManager;
#Bean
public ClientDAO clientDAO() {
SimpleJpaRepository<Client, String> support = this.getSimpleJpaRepository(Client.class);
return new MySQLClientDAO(support);
}
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Description("Hibernate repository helper")
protected <T> SimpleJpaRepository<T, String> getSimpleJpaRepository(Class<T> domainClass) {
return new SimpleJpaRepository<T, String>(domainClass, this.entityManager);
}
}
You could do something like this:
First define PropertySourcesPlaceholderConfigurer bean somewhere in your Spring configuration:
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setLocation(new ClassPathResource("application.properties"));
return ppc;
}
This configuration assumes that application.properties file is placed at the root of your classpath.
After setting up the property placeholder configurer you can access the properties in your database configuration class like so:
#Configuration
#EnableTransactionManagement
public class PersistenceConfiguration {
#Value("${spring.datasource.url}")
private String jdbcUrl;
// ...
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(jdbcUrl);
// ...
}
}
If you want an easy way to parametrize all properties, you should take a look at Spring Boot. It uses the application.properties file to automatically create data source with those properties, and many other things. This is probably the automatic datasource creation you mentioned in your question.

Categories