pavbagel pavbagel - 11 days ago 4
Java Question

@Cacheable in DAO layer not being triggered (Spring/Reddis)

I am having trouble caching internal methods within my DAO layer while in Proxy mode.

I am aware that while in Proxy mode, only external method calls coming in through the proxy are intercepted. However,I want to avoid having to switch to AspectJ mode and was wondering if any other work arounds existed.

I am displaying my code below and am wondering what changes, if any, I can add to make this process work.

--Note I am using swagger to document my code

--Also note my code has been watered down....for obvious reasons

//Controller

@RestController
@Api(produces = "application/json", protocols = "https", tags = "Securities", description = "Securities information")
public class SecuritiesInfoController extends Controller {

private SecuritiesInfoManager _securitiesInfoManager = new SecuritiesInfoManager();

@RequestMapping(value = "/security", method = RequestMethod.GET)
public List<SecuritiesInfo> getAll(){
return _securitiesInfoManager.getAll();
}
}


//Service

public class SecuritiesInfoManager extends Manager {

private SecuritiesInfoDAO _securitiesDAO = new SecuritiesInfoDAO();

public List<SecuritiesInfo> getAll() {
return _securitiesDAO.getAll();
}
}


//DAO

public class SecuritiesInfoDAO extends DAO {

private static String securitiesTable = "Securities";

@SecuritiesInfoDAOInterface

public List<SecuritiesInfo> getAll() {
//Magic
}
}


//Interface

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Cacheable(cacheNames = "SecuritiesInfo",cacheManager="cacheManager",
keyGenerator="keyGenerator" )
public @interface SecuritiesInfoDAOInterface {

}


//CacheConfig

@Configuration
//@EnableCaching(mode = AdviceMode.PROXY)
@EnableCaching(proxyTargetClass = true)
//@EnableCaching

public class CacheConfig extends CachingConfigurerSupport {

@Bean
public SecuritiesInfoDAO myService() {
// configure and return a class having @Cacheable methods
return new SecuritiesInfoDAO();
}
@Bean
public JedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();

// Defaults
redisConnectionFactory.setHostName("Nope");
redisConnectionFactory.setPort(LoL);
System.out.println("IN CONNTECTION");
redisConnectionFactory.setPassword("Please help me :)");
return redisConnectionFactory;
}


@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
System.out.println("cf: "+cf.toString());
RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
redisTemplate.setConnectionFactory(cf);
return redisTemplate;
}

/*
@Primary
@Bean
public RedisTemplate<String,ExpiringSession> redisTemplate2(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();

template.setHashValueSerializer(new LdapFailAwareRedisObjectSerializer());

template.setConnectionFactory(connectionFactory);
return template;
}
*/


@Bean
public CacheManager cacheManager(RedisTemplate<String, String> redisTemplate) {
System.out.println("IN CACHE MANAGER");
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);

// Number of seconds before expiration. Defaults to unlimited (0)
// cacheManager.setDefaultExpiration(300);
return cacheManager;
}

@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
// This will generate a unique key of the class name, the method name,
// and all method parameters appended.
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
System.out.println(sb.toString());
return sb.toString();
}
};
}

Answer

So I figured out the answer. It turns out I wasn't implementing/instantiating the interface correctly.

First I have to @Autowire my manager class in my controller. Then @autowire my interface class in my manager.

For a more detailed solution, I am placing my revised code below.

//Controller

@RestController
@Api(produces = "application/json", protocols = "https", tags =    "Securities", description = "Securities  information")
public class SecuritiesInfoController extends Controller {

@Autowired
private SecuritiesInfoManager _securitiesInfoManager = new   SecuritiesInfoManager();

@RequestMapping(value = "/security", method = RequestMethod.GET)
   public List<SecuritiesInfo> getAll(){ 
return _securitiesInfoManager.getAll(); 
 }
}

//Service

public class SecuritiesInfoManager extends Manager {

 @Autowired
    public void setSecuritiesInfoDAOInterface(SecuritiesInfoDAOInterface _securitiesInfoDAOInterface) {
        this._securitiesInfoDAOInterface = _securitiesInfoDAOInterface;
    }

public List<SecuritiesInfo> getAll() {
return _securitiesInfoDAOInterface.getAll();
 }
}

//DAO

public class SecuritiesInfoDAO extends DAO implements SecuritiesInfoDAOInterface {

private static String securitiesTable = "Securities";

@Override

public List<SecuritiesInfo> getAll() {
 //Magic
 }

}

//Interface

public interface SecuritiesInfoDAOInterface {
    @Cacheable(cacheNames = "SecuritiesInfo",cacheManager="cacheManager", keyGenerator="keyGenerator" )
    List<SecuritiesInfo> getAll();
 }
}

//CacheConfig

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Bean
public SecuritiesInfoManager myService() {
    // configure and return a class having @Cacheable methods
    return new SecuritiesInfoManager();
 }
//rest same as before
}

//WebConfig

@Configuration
@ComponentScan(basePackages = {"package name"})
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
    AntPathMatcher matcher = new AntPathMatcher();
    matcher.setCaseSensitive(false);
    configurer.setPathMatcher(matcher);
  }
 }
Comments