Skip to content

Inspired by Springboot's implementation of Redis method-caching, this repo provides auto-sync feature between datasource and cache instance using annotation based configurations.

License

vashilK/Redis-cache

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

90 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Maven Central Codacy BadgeCode Climate Known Vulnerabilities License: GPL v3 DOI

Redis-cache

Java client for redis to provide method-caching with cache synchronization feature based on Springboot's implementation of Redis with added functionality.

What is Redis-cache for?

Redis-cache is a library built on spring-redis to provide an enhanced method caching feature to your application which works at method level by using the provided annotations. diagram-redis-cache.png

Sample code

You can find a sample of the implementation here

Getting Started

To get started with Redis-Cache, first add it as a dependency in your Java project. If you're using Maven, that looks like this:

<dependency>
    <groupId>io.github.vashilk</groupId>
    <artifactId>redis-cache</artifactId>
    <version>1.0.6.1-BETA</version>
</dependency>

For Gradle:

implementation("io.github.vashilk:redis-cache:1.0.6.1-BETA")

Next you will need to connect to your Redis instance

@Configuration
public class RedisConfig {

    @Bean
    public JedisConnectionFactory connectionFactory() {
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
        configuration.setHostName("localhost");
        configuration.setPort(6379);
        return new JedisConnectionFactory(configuration);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory());
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new JdkSerializationRedisSerializer());
        template.setValueSerializer(new JdkSerializationRedisSerializer());
        template.setEnableTransactionSupport(true);
        template.afterPropertiesSet();
        return template;
    }

}

You can use your own connection to have access to a Redis-cluster with multiple redis-instances but make sure the implementation beneath uses RedisTemplate for the annotation to work properly.

Annotations

@CacheSave(group = "group-name")

Any method annotated with the one above will be cached. Designed to be used on methods that return data, specifically for heavily used ones with similar parameters.

Using annotation:

import org.nki.redis.cache.annotations.CacheSave;

@CacheSave(group = "Book")
public Book getBookById(Long id){
    // do something
}

The method above will be cache under the group "Book".

@CacheRelease(group = "group-name")

Works as a cache eviction, any method annotated with this will clear a whole group cached with the same group-name before the method runs.

Using annotation:

import org.nki.redis.cache.annotations.CacheRelease;

@CacheRelease(group = "Book")
public void resetCacheForBooks(){
    // do something
}

The method above once invoked will clear every entry in the cache for the group "Book";

@CacheSync(group = "group-name")

Methods annotated with the one above will trigger a synchronization of data for all methods annotated with @CacheSave with the same 'group-name'. This annotation is designed to be used on methods which modify the datasource from where you are querying but can be also used in events where you wish to manually trigger a synchronization.

Using annotation:

import org.nki.redis.cache.annotations.CacheSync;

@CacheSync(group = "Book")
public void saveBooks(List<Book> books){
    // do something
}

Once a method annotated with @CacheSync is invoked it will clear the cache for the group "Book" and reinvoke all the methods with parameters cached updating all the values in the cache, hence keeping the cache and data-source synchronized at all times for the group "Book".

Model

This tool serializes and deserializes models you use in your method constructors, in order for it to work properly you need to annotate the models you wish to be cached with:

@RedisCacheSerializable

Using annotation with the Object:

@Data
@RedisCacheSerializable
public class MyClass {
    private String name;
    private Boolean isAllowed;
}

Using the object in method:

public void save(MyClass myClass){
    // do something
}

Using it this way will allow easy serialization & deserialization of the object as method parameters. No adding the annotation and generating the type classes will result in code failure.

To generate the models that this tool requires please add this plugin to your pom and use this command:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>3.0.0</version>
            <executions>
                <execution>
                    <id>generate-typeReference-on-compile</id>
                    <phase>compile</phase>
                    <goals>
                        <goal>java</goal>
                    </goals>
                    <configuration>
                        <mainClass>org.nki.redis.cache.generator.ModelGenerator</mainClass>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

command:

mvn clean install

Once command run you should be able ot see all TypeReference classes for classes annotated with @RedisCacheSerializable in target > generated-sources > main > java There classes are really important to serialize and deserialize your objects in cache correctly.

Spring AOP config

Since the aspects are defined inside this library you will need make your Spring project aware of them. We are going to use the annotation based configuration method. Add the following configuration:

@Configuration
@EnableAspectJAutoProxy
public class AspectConfig {

    private final RedisTemplate<String, Object> template;
    private final ObjectMapper objectMapper;

    public AspectConfig(RedisTemplate<String, Object> template, ObjectMapper objectMapper) {
        this.template = template;
        this.objectMapper = objectMapper;
    }

    @Bean
    public CacheSyncHandler cacheSyncHandler() {
        return new CacheSyncHandler(template, objectMapper);
    }

    @Bean
    public CacheSaveHandler cacheSaveHandler() {
        return new CacheSaveHandler(objectMapper, template);
    }

    @Bean
    public CacheReleaseHandler cacheReleaseHandler() {
        return new CacheReleaseHandler(template);
    }
}

Enable Logging

If you require details of when the aspects are triggering and the details of the operation, add this to your application.properties file.

redis-cache.enable.logs = true

Compilation issues

If your code includes Lombok as a dependecy and you experience any build issues with your code after adding the dependencies and plugins in intelliJ idea before deployment do the following:

Go to Project Structure, Modules, select AspectJ and check Post-compile weave mode. This will ensure ajc runs after Lombok and can see the generated classes.

Errors connecting to Redis

Add these to your application.properties file.

spring.redis.host = localhost
spring.redis.port = 6379

Contributing

This is a completely open source project, it is an idea that came up to me when using Redis in one of my projects. All help and collaborations to refine and make this strong solution are welcome you can contact me at my LinkedIn.

About

Inspired by Springboot's implementation of Redis method-caching, this repo provides auto-sync feature between datasource and cache instance using annotation based configurations.

Topics

Resources

License

Stars

Watchers

Forks