1

I'm learning redis. Now facing a problem with redis cache. I'm calling a method of a service class with same value but it seems it is executed each time.

When I am calling getEmployeesByClient() method of EmployeeService from ThreadService I am expecting for a new client I will see the log Inside of getEmployeeByClient. But for next calling I will get list from cache, then it will not give data from repository.

But I'm getting the log Inside of getEmployeeByClient each time I'm calling the method getEmployeesByClient() of EmployeeService with same argument. I have provided my log as well at the end of this section.

I have seen some questions of this site like this: Spring boot caching in @Service class does not work

But have not got solution.

I'm providing my related codes:

My ThreadService class:

@Service
@Slf4j
public class ThreadService implements Runnable {

    @Autowired
    private EmployeeService employeeService;

    public static boolean isRunning = true;

    @PostConstruct
    @Override
    public void run() {
        log.debug("Service Thread Started");
        while(isRunning) {
            log.debug("repository calling...");    
            List<Employee> employees = employeeService.getEmployeesByClient("FastVoiz");
            log.debug("Employee Size: " + employees.size());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                log.error("Exception: ", e);
            }
        }
    }
}

EmployeeService class:

@Service
@Slf4j
public class EmployeeService {

    @Autowired
    private EmployeeRepository repository;

    @Cacheable(value = "employeeCache", key = "#client")
    public List<Employee> getEmployeesByClient(String client) {
        log.debug("Inside of getEmployeeByClient");
        return repository.findEmployeesByClient(client);
    }
}

RedisConfiguration class:

@Configuration
@EnableCaching
@PropertySource("classpath:application.properties")
public class RedisConfiguration {
    @Autowired
    private Environment env;

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisConf = new RedisStandaloneConfiguration();
        redisConf.setHostName(env.getProperty("spring.redis.host"));
        redisConf.setPort(Integer.parseInt(env.getProperty("spring.redis.port")));
        redisConf.setPassword(RedisPassword.of(env.getProperty("spring.redis.password")));
        return new LettuceConnectionFactory(redisConf);
    }
    @Bean
    public RedisCacheConfiguration cacheConfiguration() {
        RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .disableCachingNullValues();
        return cacheConfig;
    }
    @Bean
    public RedisCacheManager cacheManager() {
        RedisCacheManager rcm = RedisCacheManager.builder(redisConnectionFactory())
                .cacheDefaults(cacheConfiguration())
                .transactionAware()
                .build();
        return rcm;
    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demoNaz</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demoNaz</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <maven.test.skip>true</maven.test.skip>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!--to run jar file-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <finalName>demoNaz</finalName>
    </build>

</project>

application.properties file:

#JPA configuration
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.show-sql=true
spring.data.jpa.repositories.enabled=true
spring.jpa.database=POSTGRESQL
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.properties.hibernate.id.new_generator_mappings=false
spring.jpa.properties.hibernate.format_sql=true 

#datasource
spring.datasource.url=jdbc:postgresql://localhost:5432/testDB
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.initialization-mode=always
#spring.datasource.initialize=true
#spring.datasource.schema=classpath:/schema.sql
spring.datasource.continue-on-error=true
spring.datasource.platform=postgres

#redis
spring.redis.host=localhost
spring.redis.timeout=2000
spring.redis.password=password
spring.redis.port=6379

#redis cache manager configuration
spring.cache.type=redis
spring.cache.redis.cache-null-values=false
spring.cache.redis.time-to-live=600000
spring.cache.redis.use-key-prefix=true

#redis-lettuce configuration
spring.redis.lettuce.pool.max-active=7 
spring.redis.lettuce.pool.max-idle=7
spring.redis.lettuce.pool.min-idle=2
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.shutdown-timeout=200ms

#logging
logging.level.root=DEBUG
logging.file=demoApp.log

#others
spring.main.allow-bean-definition-overriding=true

Here is my some log:

2019-10-13 20:17:29.619 DEBUG 12932 --- [           main] c.example.demoNaz.service.ThreadService  : First line of thread
2019-10-13 20:17:29.619 DEBUG 12932 --- [           main] c.e.demoNaz.service.EmployeeService      : Inside of getEmployeeByClient
2019-10-13 20:17:29.620 DEBUG 12932 --- [           main] tor$SharedEntityManagerInvocationHandler : Creating new EntityManager for shared EntityManager invocation
2019-10-13 20:17:29.620 DEBUG 12932 --- [           main] o.h.q.c.internal.CriteriaQueryImpl       : Rendered criteria query -> select generatedAlias0 from Employee as generatedAlias0 where generatedAlias0.client=:param0
2019-10-13 20:17:29.620 DEBUG 12932 --- [           main] org.hibernate.SQL                        : select employee0_.id as id1_0_, employee0_.acc as acc2_0_, employee0_.client as client3_0_ from employee employee0_ where employee0_.client=?
Hibernate: select employee0_.id as id1_0_, employee0_.acc as acc2_0_, employee0_.client as client3_0_ from employee employee0_ where employee0_.client=?
2019-10-13 20:17:29.622 DEBUG 12932 --- [           main] org.hibernate.loader.Loader              : Result set row: 0
2019-10-13 20:17:29.622 DEBUG 12932 --- [           main] org.hibernate.loader.Loader              : Result row: EntityKey[com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:29.622 DEBUG 12932 --- [           main] o.h.engine.internal.TwoPhaseLoad         : Resolving associations for [com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:29.622 DEBUG 12932 --- [           main] o.h.engine.internal.TwoPhaseLoad         : Done materializing entity [com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:29.623 DEBUG 12932 --- [           main] c.example.demoNaz.service.ThreadService  : Employee Size: 1
2019-10-13 20:17:32.258 DEBUG 12932 --- [l-1 housekeeper] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Pool stats (total=10, active=0, idle=10, waiting=0)
2019-10-13 20:17:34.623 DEBUG 12932 --- [           main] c.example.demoNaz.service.ThreadService  : First line of thread
2019-10-13 20:17:34.624 DEBUG 12932 --- [           main] c.e.demoNaz.service.EmployeeService      : Inside of getEmployeeByClient
2019-10-13 20:17:34.625 DEBUG 12932 --- [           main] tor$SharedEntityManagerInvocationHandler : Creating new EntityManager for shared EntityManager invocation
2019-10-13 20:17:34.625 DEBUG 12932 --- [           main] o.h.q.c.internal.CriteriaQueryImpl       : Rendered criteria query -> select generatedAlias0 from Employee as generatedAlias0 where generatedAlias0.client=:param0
2019-10-13 20:17:34.627 DEBUG 12932 --- [           main] org.hibernate.SQL                        : select employee0_.id as id1_0_, employee0_.acc as acc2_0_, employee0_.client as client3_0_ from employee employee0_ where employee0_.client=?
Hibernate: select employee0_.id as id1_0_, employee0_.acc as acc2_0_, employee0_.client as client3_0_ from employee employee0_ where employee0_.client=?
2019-10-13 20:17:34.628 DEBUG 12932 --- [           main] org.hibernate.loader.Loader              : Result set row: 0
2019-10-13 20:17:34.629 DEBUG 12932 --- [           main] org.hibernate.loader.Loader              : Result row: EntityKey[com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:34.630 DEBUG 12932 --- [           main] o.h.engine.internal.TwoPhaseLoad         : Resolving associations for [com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:34.630 DEBUG 12932 --- [           main] o.h.engine.internal.TwoPhaseLoad         : Done materializing entity [com.example.demoNaz.entity.Employee#13002]
2019-10-13 20:17:34.631 DEBUG 12932 --- [           main] c.example.demoNaz.service.ThreadService  : Employee Size: 1
2019-10-13 20:17:39.633 DEBUG 12932 --- [           main] c.example.demoNaz.service.ThreadService  : First line of thread
2019-10-13 20:17:39.633 DEBUG 12932 --- [           main] c.e.demoNaz.service.EmployeeService      : Inside of getEmployeeByClient
Mukit09
  • 2,956
  • 3
  • 24
  • 44

1 Answers1

1

First of all, you are not supposed to use any of those services in the PostConstruct phase because you have no guarantee that the proxy interceptor has fully started at this point. If you have to do something, after application context is initialized, try implementing InitializingBean and override afterPropertiesSet() method, or listen to Application Context event like ContextRefreshedEvent. Start your thread there. This will ensure that all other bean has been initialized.

Now, coming to your problem, this occurs, because your cache interceptor is not initialized. A workaround solution is to manually initialize the interceptor. For that you can do something like this,

    @Configuration
    public class ConfigClass{
        @Autowired
        private CacheInterceptor cacheInterceptor;

        @PostConstruct
        public void init(){

            cacheInterceptor.afterSingletonsInstantiated();
        }
    }

this will work.

Also add spring-boot-starter-cache in your dependency https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-cache

Alam
  • 351
  • 1
  • 5
  • 14