What strategies exist for using Spring Cache on methods that take an array or collection parameter? - spring

I want to use Spring's Cache abstraction to annotate methods as #Cacheable. However, some methods are designed to take an array or collection of parameters and return a collection. For example, consider this method to find entites:
public Collection<Entity> getEntities(Collection<Long> ids)
Semantically, I need to cache Entity objects individually (keyed by id), not based on the collection of IDs as a whole. Similar to what this question is asking about.
Simple Spring Memcached supports what I want, via its ReadThroughMultiCache, but I want to use Spring's abstraction in order to support easy changing of the cache store implementation (Guava, Coherence, Hazelcast, etc), not just memcached.
What strategies exist for caching this kind of method using Spring Cache?

Spring's Cache Abstraction does not support this behavior out-of-the-box. However, it does not mean it is not possible; it's just a bit more work to support the desired behavior.
I wrote a small example demonstrating how a developer might accomplish this. The example uses Spring's ConcurrentMapCacheManager to demonstrate the customizations. This example will need to be adapted to your desired caching provider (e.g. Hazelcast, Coherence, etc).
In short, you need to override the CacheManager implementation's method for "decorating" the Cache. This varies from implementation to implementation. In the ConcurrentMapCacheManager, the method is createConcurrentMapCache(name:String). In Spring Data GemFire, you would override the getCache(name:String) method to decorate the Cache returned. For Guava, it would be the createGuavaCache(name:String) in the GuavaCacheManager, and so on.
Then your custom, decorated Cache implementation (perhaps/ideally, delegating to the actual Cache impl, from this) would handle caching Collections of keys and corresponding values.
There are few limitations of this approach:
A cache miss is all or nothing; i.e. partial keys cached will be considered a miss if any single key is missing. Spring (OOTB) does not let you simultaneously return cache values and call the method for the diff. That would require some very extensive modifications to the Cache Abstraction that I would not recommend.
My implementation is just an example so I chose not to implement the Cache.putIfAbsent(key, value) operation (here).
While my implementation works, it could be made more robust.
Anyway, I hope it provides some insight in how to handle this situation properly.
The test class is self-contained (uses Spring JavaConfig) and can run without any extra dependencies (beyond Spring, JUnit and the JRE).
Cheers!

Worked for me. Here's a link to my answer.
https://stackoverflow.com/a/60992530/2891027
TL:DR
#Cacheable(cacheNames = "test", key = "#p0")
public List<String> getTestFunction(List<String> someIds) {
My example is with String but it also works with Integer and Long, and probably others.

Related

Implement "cache tags pattern" in Spring

I have been searching for long time in the Internet, if Spring supports the "cache tag pattern" but seems it doesn't.... How do you implement this cache pattern in Spring???
An example of this cache pattern can be seen in Drupal cache tag implementation, I will create an example of how would that look
#Service
#AllArgsConstructor
class TicketService {
private final UserRepository userRepository;
private final ProductRepository productRepository;
private final TicketRepository ticketRepository;
#Cacheable(cacheNames = "global-tags-cache", tags = { "ticket:list", "user:#{user.id}", "product:#{product.id}"})
public List<TicketDto> findTicketsForUserThatIncludesProduct(User user, Product product) {
var tickets = ticketRepository.findByUserAndProduct(user, product);
}
#CacheEvict(cacheNames = "global-tags-cache", tags = "ticket:list")
public Ticket saveNewTicket(TicketRequestDto ticketRequestDto) { ... }
}
#Service
#AllArgsConstructor
class ProductService {
private final ProductRepository productRepository;
#CacheEvict(cacheNames = "global-tags-cache", tags = "product:#{productRequestDto.id}")
public Product updateProductInformation(ProductRequestDto productRequestDto() {
...
}
}
#Service
class NonTagCacheService() {
#Cacheable(cacheNames = "some-non-global-cache-store")
public Object doStrongComputation() { ... }
}
The idea is to handle the responsability of the "tag eviction" where it belongs to, for example TicketService wants its cache to be break when user is altered, or when any ticket is altered, or when the specified product is altered... TicketService doesn't need to know when or where Product is going to clear its tag
This pattern is strongly useful in Drupal, and makes its cache very powerfull, this is just an example, but one can implement its own tags for whatever reason he wants, for example a "kafka-process:custom-id"
As M. Deinum explained, Spring's Cache Abstraction is just that, an "abstraction", or rather an SPI enabling different caching providers to be plugged into the framework in order to offer caching capabilities to managed application services (beans) where needed, not unlike Security, or other cross-cutting concerns.
Spring's Cache Abstraction only declares fundamental, but essential caching functions that are common across most caching providers. In effect, Spring's Cache Abstraction implements the lowest common denominator of caching capabilities (e.g. put and get). You can think of java.util.Map as the most basic, fundamental cache implementation possible, and is indeed one of the many supported caching providers offered out of the box (see here and here).
This means advanced caching functions, such as expiration, eviction, compression, serialization, general memory management and configuration, and so on, are left to individual providers since these type of capabilities vary greatly from one cache implementation (provider) to another, as does the configuration of these features. This would be no different in Drupal's case. The framework documentation is definitive on this matter.
Still, not all is lost, but it usually requires a bit of work on the users part.
Being that the Cache and CacheManager interfaces are the primary interfaces (SPI) of the Spring Cache Abstraction, it is easy to extend or customize the framework.
First, and again, as M. Deinum points out, you have the option of custom key generation. But, this offers no relief with respect to (custom) eviction policies based on the key(s) (or tags applied to cache entries).
Next, you do have the option to get access to the low-level, "native" cache implementation of the provider using the API, Cache.getNativeCache(). Of course, then you must forgo the use of Spring Cache Annotations, or alternatively, the JCAche API Annotations, supported by Spring, which isn't as convenient, particularly if you want to enable/disable caching conditionally.
Finally, I tested a hypothesis to a question posted in SO not long ago regarding a similar problem... using Regular Expressions (REGEX) to evict entries in a cache where the keys matched the REGEX. I never provided an answer to this question, but I did come up with a "generic" solution, implemented with 3 different caching providers: Redis, Apache Geode, and using the simple ConcurrentMap implementation.
This involved a significant amount of supporting infrastructure classes, beginning here and declared here. Of course, my goal was to implement support for multiple caching providers via "decoration". Your implementation need not be so complicated, or rather sophisticated, ;-)
Part of my future work on the Spring team will involve gathering use cases like yours and providing (pluggable) extensions to the core Spring Framework Cache Abstraction that may eventually find its way back into the core framework, or perhaps exist as separate pluggable modules based on application use case and requirements that our many users have expressed over the years.
At any rate, I hope this offers you some inspiration on how to possibly and more elegantly handle your use case.
Always keep in mind the Spring Framework is an exceptional example of the Open/Closed principle; it offers many extension points, and when combined with the right design pattern (e.g. Decorator, not unlike AOP itself), it can be quite powerful.
Good luck!

A question regarding DAO vs Repository patterns

I am new to repositories and I am a bit confused at the moment. From what I have read, DAO pattern is where you provide methods to access the the data store. Though, with repository, you access the datastore with an object repo.
I saw two examples here:
https://medium.com/#gustavo.ponce.ch/spring-boot-spring-mvc-spring-security-mysql-a5d8545d837d
http://javainsimpleway.com/spring-mvc-with-hibernate-crud-example/
The first example extends JpaRepository as intended, and no implementations are available (for add, remove, etc).
The second example provides DAO access with methods, though it goes with service/repository implementation. I mean it uses #Repository and #Service even though it is DAO.
Which one is the right implementation handling repositories.
Thanks for your time.
I recommend reading this article.
A DAO is much closer to the underlying storage , it's really data
centric. That's why in many cases you'll have DAOs matching db tables
or views 1 on 1.
A repository sits at a higher level. It deals with data too and hides
queries and all that but, a repository deals with** business/domain
objects**.

Spring Caching not working for findAll method

I have recently started working on caching the result from a method. I am using #Cacheable and #CachePut to implement the desired the functionality.
But somehow, the save operation is not updating the cache for findAll method. Below is the code snippet for the same:
#RestController
#RequestMapping(path = "/test/v1")
#CacheConfig(cacheNames = "persons")
public class CacheDemoController {
#Autowired
private PersonRepository personRepository;
#Cacheable
#RequestMapping(method = RequestMethod.GET, path="/persons/{id}")
public Person getPerson(#PathVariable(name = "id") long id) {
return this.personRepository.findById(id);
}
#Cacheable
#RequestMapping(method = RequestMethod.GET, path="/persons")
public List<Person> findAll() {
return this.personRepository.findAll();
}
#CachePut
#RequestMapping(method = RequestMethod.POST, path="/save")
public Person savePerson(#RequestBody Person person) {
return this.personRepository.save(person);
}
}
For the very first call to the findAll method, it is storing the the result in the "persons" cache and for all the subsequent calls it is returning the same result even if the save() operation has been performed in between.
I am pretty new to caching so any advice on this would be of great help.
Thanks!
So, a few things come to mind regarding your UC and looking at your code above.
First, I am not a fan of users enabling caching in either the UI or Data tier of the application, though it makes more sense in the Data tier (e.g. DAOs or Repos). Caching, like Transaction Management, Security, etc, is a service-level concern and therefore belongs in the Service tier IMO, where your application consists of: [Web|Mobile|CLI]+ UI -> Service -> DAO (a.k.a. Repo). The advantage of enabling Caching in the Service tier is that is is more reusable across your application/system architecture. Think, servicing Mobile app clients in addition to Web, for instance. Your Controllers for you Web tier may not necessarily be the same as those handling Mobile app clients.
I encourage you to read the chapter in the core Spring Framework's Reference Documentation on Spring's Cache Abstraction. FYI, Spring's Cache Abstraction, like TX management, is deeply rooted in Spring's AOP support. However, for your purposes here, let's break your Spring Web MVC Controller (i.e. CacheDemoController) down a bit as to what is happening.
So, you have a findAll() method that you are caching the results for.
WARNING: Also, I don't generally recommend that you cache the results of a Repository.findAll() call, especially in production! While this might work just fine locally given a limited data set, the CrudRepository.findAll() method returns all results in the data structure in the backing data store (e.g. the Person Table in an RDBMS) for that particular object/data type (e.g. Person) by default, unless you are employing paging or some LIMIT on the result set returned. When it comes to caching, always think a high degree of reuse on relatively infrequent data changes; these are good candidates for caching.
Given your Controller's findAll() method has NO method parameters, Spring is going to determine a "default" key to use to cache the findAll() method's return value (i.e. List<Person).
TIP: see Spring's docs on "Default Key Generation" for more details.
NOTE: In Spring, as with caching in general, Key/Value stores (like java.util.Map) are the primary implementation's for Spring's notion of a Cache. However, not all "caching providers" are equal (e.g. Redis vs. a java.util.concurrent.ConcurrentHashMap, for instance).
After calling the findAll() Controller method, your cache will have...
KEY | VALUE
------------------------
abc123 | List of People
NOTE: the cache will not store each Person in the list individually as a separate cache entry. That is not how method-level caching works in Spring's Cache Abstraction, at least not by default. However, it is possible.
Then, suppose your Controller's cacheable getPerson(id:long) method is called next. Well, this method includes a parameter, the Person's ID. The argument to this parameter will be used as the key in Spring's Cache Abstraction when the Controller getPerson(..) method is called and Spring attempts to find the (possibly existing) value in the cache. For example, say the method is called with controller.getPerson(1). Except a cache entry with key 1 does not exist in the cache, even if that Person (1) is in list mapped to key abc123. Thus, Spring is not going to find Person 1 in the list and return it, and so, this op results in a cache miss. When the method returns the value (the Person with ID 1) will be cached. But, the cache now looks like this...
KEY | VALUE
------------------------
abc123 | List of People
1 | Person(1)
Finally, a user invokes the Controller's savePerson(:Person) method. Again, the savePerson(:Person) Controller method's parameter value is used as the key (i.e. a "Person" object). Let's say the method is called as so, controller.savePerson(person(1)). Well, the CachePut happens when the method returns, so the existing cache entry for Person 1 is not updated since the "key" is different, so a new cache entry is created, and your cache again looks like this...
KEY | VALUE
---------------------------
abc123 | List of People
1 | Person(1)
Person(1) | Person(1)
None of which is probably what you wanted nor intended to happen.
So, how do you fix this. Well, as I mentioned in the WARNING above, you probably should not be caching an entire collection of values returned from an op. And, even if you do, you need to extend Spring's Caching infrastructure OOTB to handle Collection return types, to break the elements of the Collection up into individual cache entries based on some key. This is intimately more involved.
You can, however, add better coordination between the getPerson(id:long) and savePerson(:Person) Controller methods, however. Basically, you need to be a bit more specific about your key to the savePerson(:Person) method. Fortunately, Spring allows you to "specify" the key, by either providing s custom KeyGenerator implementation or simply by using SpEL. Again, see the docs for more details.
So your example could be modified like so...
#CachePut(key = "#result.id"
#RequestMapping(method = RequestMethod.POST, path="/save")
public Person savePerson(#RequestBody Person person) {
return this.personRepository.save(person);
}
Notice the #CachePut annotation with the key attribute containing the SpEL expression. In this case, I indicated that the cache "key" for this Controller savePerson(:Person) method should be the return value's (i.e. the "#result") or Person object's ID, thereby matching the Controller getPerson(id:long) method's key, which will then update the single cache entry for the Person keyed on the Person's ID...
KEY | VALUE
---------------------------
abc123 | List of People
1 | Person(1)
Still, this won't handle the findAll() method, but it works for getPerson(id) and savePerson(:Person). Again, see my answers to the posting(s) on Collection values as return types in Spring's Caching infrastructure and how to handle them properly. But, be careful! Caching an entire Collection of values as individual cache entries could reck havoc on your application's memory footprint, resulting in OOME. You definitely need to "tune" the underlying caching provider in this case (eviction, expiration, compression, etc) before putting a large deal of entires in the cache, particular at the UI tier where literally thousands of requests maybe happening simultaneously, then "concurrency" becomes a factor too! See Spring's docs on sync capabilities.
Anyway, hope this helps aid your understanding of caching, with Spring in particular, as well as caching in general.
Cheers,
-John

Autowire two Neo4j GraphRepository in Spring

I'm new to using Spring with Neo4j and I have a question about #Autowire for a GraphRepository.
Most examples I've seen use one #Autowire per Controller, but I have two Nodes I need to modify at the same time when a particular method is called in the controller. Should I simply #Autowire the repositories for both nodes (eg per the code below)? Is there any impact if I do this in a second controller with the same repositories as well (so if I had a ChatSessionController which also #Autowired ChatMessageService and ChatSessionService)?
ChatMessageController.java
#Controller
public class ChatMessageController {
#Autowired
private ChatMessageService chatMessageService;
#Autowired
private ChatSessionService chatSessionService;
#RequestMapping(value = "/message/add/{chatSessionId}", method = RequestMethod.POST)
#ResponseBody
#Transactional
public void addMessage(#RequestBody ChatMessagePack chatMessagePack,
#PathVariable("chatSessionId") Long chatSessionId) {
ChatMessage chatMessage = new ChatMessage(chatMessagePack);
chatMessageService.save(chatMessage);
// TODO: Make some modifications to the ChatSession as well
}
}
Any help would be much appreciated! I've been googling and looking through Stackoverflow to understand this better but I haven't found anything yet. Any pointers in the right directions would be great.
Another underlying question is, should I be (and can I?) modifying other Nodes in a GraphRepository that handles a particular node? Eg Should my GraphRepository be able to modify my GraphRespository?
Thanks!
I'm not convinced that this is a SO question, it's not really a Neo4J or Spring question either, it is more about the architecture of your application. However assuming that you understand the negatives of class fan out, and how to use the #Transactional annotation to achieve what you want then the answer to your question is that it is just fine to have many Repositories (Neo4J or otherwise, autowired or otherwise) in your class and in as many classes as you want.
Neo4J transactions default to Isolation level READ_COMMITTED and if you need anything else, you need to add the guards/locks yourself. Nested transactions are consideredd tobe the same transaction. The Spring #Transactional annotation relies on proxies that you should be aware of as they have implications when calling methods from within the same class.
I would go through this tuotorial over at Spring Data and get your head around how real world vs domain vs node models differ, there will be cases where one repository impacts another node type but I would think it is often transparent to you (i.e adding relationships). You can do what you like in each repository (the generic nature of them is largely confined to all of the built in CRUD and queries derived from finder-method names (see documentation ) using the #Query annotation, and some queries have side effects, but largely you should avoid it.
As you start adding multiple repositories to multiple controllers I think that your code will begin to smell bad and that you should consider encapsulating this business logic off on its own somewhere, neatly unit tested. I also wouldn't tie myself to one controller per data object, it would be fine to have a single ChatController with a POST/chat/ to create a new session and POST /chat/{sessionId} to add a message. Intersting questions on Programmers:
How accurate is "Business logic should be in a service, not in a model?"
Best Practices for MVC Architecture
MVC Architecture — How many Controllers do I need?

How to add a custom ContentHander for JAXB2 support in Spring 3 (MVC)?

Scenario: I have a web application that uses Spring 3 MVC. Using the powerful new annotations in Spring 3 (#Controller, #ResponseBody etc), I have written some domain objects with #XML annotations for marhalling ajax calls to web clients. Everything works great. I declared my Controller class to have a return type #ResponseBody with root XML object - the payload gets marshalled correctly and sent to Client.
The problem is that some data in the content is breaking the XML compliance. I need to wrap this with CDATA when necessary. I saw a POST here How to generate CDATA block using JAXB? that recommends using a custom Content Handler. Ok, fantastic!
public class CDataContentHandler extends (SAXHandler|XMLSerializer|Other...) {
// see http://www.w3.org/TR/xml/#syntax
private static final Pattern XML_CHARS = Pattern.compile("[<>&]");
public void characters(char[] ch, int start, int length) throws SAXException {
boolean useCData = XML_CHARS.matcher(new String(c,start,length)).find();
if (useCData) super.startCDATA();
super.characters(ch, start, length);
if (useCData) super.endCDATA();
}
}
Using Spring MVC 3, how do I achieve this? Everything was "auto-magically" done for me with regards to the JAXB aspects of setup, Spring read the return type of the method, saw the annotations of the return type and picked up JAXB2 off the classpath to do the marshalling (Object to XML conversion). So where on earth is the "hook" that permits a user to register a custom Content Handler to the config?
Using EclipseLink JAXB implementation it is as easy as adding #XmlCDATA to the Object attribute concerned. Is there some smart way Spring can help out here / abstract this problem away into a minor configuration detail?
I know Spring isn't tied to any particular implementation but for the sake of this question, please can we assume I am using whatever the default implementation is. I tried the Docs here http://static.springsource.org/spring-ws/site/reference/html/oxm.html but it barely helped at all with this question from what I could understand.
Thanks all for any replies, be really appreciated.
Update:
Thanks for the suggested answer below Akshay. It was sufficient to put me on right tracks. Investigating further, I see there is a bit of history with this one between Spring version 3.05 and 3.2. In Spring 3.05 it used to be quite difficult to register a custom MessageConverter (this is really the goal here).
This conversation pretty much explains the thinking behind the development changes requested:
https://jira.springsource.org/browse/SPR-7504
Here is a link to the typically required class override to build a cusom solution:
http://static.springsource.org/spring/docs/3.1.0.M1/javadoc-api/org/springframework/http/converter/AbstractHttpMessageConverter.html
And the following Question on stack overflow is very similar to what I was asking for (except the #ResponseBody discussion relates to JSON and jackson) - the goal is basically the same.
Spring 3.2 and Jackson 2: add custom object mapper
So it looks like usage of , and overriding MarshallingHttpMessageConverter is needed, registering to AnnotationMethodHandlerAdapter. There is a recommended solution in link above to also get clever with this stuff and wrap the whole thing behind a custom defined Annotation.
I haven't yet developed a working solution but since I asked the questions, wanted to at least post something that may help others with the same sort of question, to get started. With all due respect, although this has all improved in Spring 3.2, it's still bit of a dogs dinner to get a little customization working... I really was expecting a one liner config change etc.
Rather than twist and bend Spring, perhaps the easiest answer for my particular issue is just to change JAXB2 implementation and use something like Eclipse Link JAXB that can do this out of the box.
Basically you need to create a custom HttpMessageConverter. Instead of relying on the Jaxb2RootElementHttpMessageConverter that spring uses by default.
Unfortunately, customizing one converter means you are telling spring that you will take care of loading all the converters you need! Which is fairly involved and can get complicated, based on whether you use annotations, component scanning, Spring 3.1 or earlier, etc.. The issue of how to add a custom converter is addressed here: Custom HttpMessageConverter with #ResponseBody to do Json things
In your custom message converter you are free to use any custom JAXB2 content handlers.
Another, simpler approach to solve your original problem would be to use a custom XmlJavaTypeAdapter. Create a custom implementation of javax.xml.bind.annotation.adapters.XmlAdapter to handle CDATA, in the marshal method wrap the return value with the cdata braces. Then in your mapped pojo, use the XmlAdapter annotation, pass it the class of your custom adapter and you should be done.
I have not myself implemented the adapter approach, so couldn't provide sample code. But it should work, and won't be a lot of work.
Hope this helps.

Resources