when I use spring cache with redis, I use it in two app, the one read and write,the other is only read,how can I config?
I try do like this, but it does not work!
#Cacheable(value = "books", key = "#isbn", condition = "false")
Can anyone help ?
You have misunderstood the purpose of the #Cacheable annotation's "condition" attribute. Per the documentation...
If true, the method is cached - if not, it behaves as if the method is
not cached, that is executed every since time no matter what values
are in the cache or what arguments are used.
The condition attribute just determines whether the cache (e.g. Redis) is consulted first, before executing the (potentially expensive) method. If condition evaluates to false, then the method will always be executed and the result subsequently cached.
In the read-only app, I am assuming you want the cache consulted first, if the value is not in the cache, then execute the method, however, DO NOT cache the result. Is this correct?
If so, then you only need specify the unless attribute instead of the condition attribute like so...
#Cacheable(value="books", key="#isbn", unless="true")
void someBookMutatingOperation(String isbn, ...) { .. }
If, however, you want to avoid the cacheable method invocation in the read-only (version of the) app altogether and just consult the cache regardless of whether a value actually exists in the cache or not, then your problem is quite a bit more complex/difficult.
Spring's Cache Abstraction operates on the premise that if a value is not in the cache then it will return null to indicate a cache miss, which is then followed by a subsequent method invocation. Only when a cache returns a value for the specified key(s) will the method invocation be avoided.
Without a custom extension (perhaps using (additional) AOP interceptors) there is no way to avoid the OOTB behavior.
I will not elaborate on this later technique unless your use case requires it.
Hope this helps.
#John Blum
thanks! happy new year.
your answer inspired me, I have read a part of the spring cache source code. the CacheInterceptor class. the CacheAspectSupport class.
private Object execute(CacheOperationInvoker invoker, CacheOperationContexts contexts) {
// Process any early evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), true, ExpressionEvaluator.NO_RESULT);
// Check if we have a cached item matching the conditions
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
// Collect puts from any #Cacheable miss, if no cached item is found
List<CachePutRequest> cachePutRequests = new LinkedList<CachePutRequest>();
if (cacheHit == null) {
collectPutRequests(contexts.get(CacheableOperation.class), ExpressionEvaluator.NO_RESULT, cachePutRequests);
}
Cache.ValueWrapper result = null;
// If there are no put requests, just use the cache hit
if (cachePutRequests.isEmpty() && !hasCachePut(contexts)) {
result = cacheHit;
}
// Invoke the method if don't have a cache hit
if (result == null) {
result = new SimpleValueWrapper(invokeOperation(invoker));
}
// Collect any explicit #CachePuts
collectPutRequests(contexts.get(CachePutOperation.class), result.get(), cachePutRequests);
// Process any collected put requests, either from #CachePut or a #Cacheable miss
for (CachePutRequest cachePutRequest : cachePutRequests) {
cachePutRequest.apply(result.get());
}
// Process any late evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, result.get());
return result.get();
}
I think should prevent the cachePutRequest execute. if no cache be hit, to invoke the method body of #Cacheable and don't cached the result. use unless will prevent the method invoke. Is this correct?
#Tonney Bing
First of all, my apologies for misguiding you on my previous answer...
If condition evaluates to false, then the method will always be
executed and the result subsequently cached.
The last part is NOT true. In fact, the condition attribute does prevent the #Cacheable method result from being cached. But, neither the condition nor the unless attribute prevent the #Cacheable service method from being invoked.
Also, my code example above was not correct. The unless attribute needs to be set to true to prevent caching of the #Cacheable method result.
After re-reading this section in the Spring Reference Guide, I came to realize my mistake and wrote an example test class to verify Spring's "conditional" caching behavior.
So...
With respect to your business use case, the way I understand it based on your original question and subsequently, your response to my previous answer, you have a #Cacheable service method that needs to be suppressed of invocation in the read-only app regardless of whether the value is in the cache or not! In other words, the value should always be retrieved from the cache and the #Cacheable service method should NOT be invoked in read-only mode.
Now to avoid polluting your application code with Spring infrastructure component references, and specifically, with a Spring CacheManager, this is a good example of a "cross-cutting concern" (since multiple, mutating-based application service operations may exist) and therefore, can be handled appropriately using AOP.
I have coded such an example satisfying your requirements here.
This is a self-contained test class. The key characteristics of this test class include...
The use of external configuration (by way of the app.mode.read-only System property) to determine if the app is in read-only mode.
The use of AOP and a custom Aspect to control whether the subsequent invocation of the Joint Point (i.e. the #Cacheable service method) is allowed (no, in a read-only context). In addition, I appropriately set the order in which the Advice (namely, the #Cacheable based advice along with the handleReadOnlyMode advice in the UseCacheExclusivelyInReadOnlyModeAspect Aspect) should fire based on precedence.
Take note of the #Cacheable annotation on the service method...
#Cacheable(value = "Factorials", unless = "T(java.lang.System).getProperty('app.mode.read-only', 'false')")
public Long factorial(long number) { .. }
You can see the intended behavior with the System.err output statements in the test class.
Hope this helps!
Related
I'm using spark-solr in order to perform Solr queries. However, my searches don't work as they're supposed to because for some reason the requests being generated by spark prevent the searches from being distributed. I have discovered it by looking at the Solr logs where I saw that a distrib=false parameter is added to the sent requests. When executing the queries manually (not using spark) with distrib=true the results were fine.
I was trying to set the parameters sent by spark by changing the "solr.params" value in the options dictionary (I'm using pyspark):
options = {
"collection": "collection_name",
"zkhost": "server:port",
"solr.params": "distrib=true"
}
spark.read.format("solr").options(**options).load().show()
This change did not have any effect: I still see in the logs that a distrib=false parameter is being sent. Other parameters passed through the "solr.params" key (such as fq=something) do have an effect on the results. But it looks like spark insists on sending distrib=false no matter what I do.
How do I force a distributed search through spark-solr?
The easy solution is to configure the request handler to run distributed queries using an invariant. The invariant forces the distrib parameter to have a true value even if spark-solr is trying to change it in query time. Introducing the invariant can be done by adding the following lines under the definition of your request handler entry in solrconfig.xml:
<lst name="invariants">
<str name="distrib">true</str>
</lst>
While the introduction of the invariant is going to fix the problem, I think it's kind of a radical solution. This is because the solution involves hiding a behavior in which you overload the value of a parameter. By introducing the invariant you cannot decide to set distrib to false: even if your request explicitly does so, the value of distrib would still be true. This is too risky in my opinion and that's why I'm suggesting another solution which might be harder to implement but wouldn't suffer from that flaw.
The solution is to implement a query component which is going to force distrib=true only when receiving a forceDistrib=true flag as a parameter.
public class ForceDistribComponent extends SearchComponent {
private static String FORCE_DISTRIB_PARAM = "forceDistrib";
#Override
public void prepare(ResponseBuilder rb) throws IOException {
ModifiableSolrParams params = new ModifiableSolrParams(rb.req.getParams());
if (!params.getBool(FORCE_DISTRIB_PARAM, false)) return;
params.set(CommonParams.DISTRIB, true);
params.set(FORCE_DISTRIB_PARAM, false);
rb.req.setParams(params);
}
}
After building the component you can configure solr to use it by adding the component to solrconfig.xml and set your request handler to use it.
Adding the component to solrconfig.xml is done by adding the following entry to the solrconfig.xml file:
<searchComponent name="forceDistrib" class="ForceDistribComponent"/>
Configuring the request handler to use the forceDistrib component is done by adding it to the list of components under the request handler entry. It must be the first component in the list:
<arr name="components">
<str>forceDistrib</str>
<str>query</str>
...
</arr>
This solution, while more involved than simply introducing an invariant, is much safer.
I has one method to call another #Cacheable method like this:
public ItemDO findMethod2(long itemId) {
this.findMethod1(itemId);
...
}
#Cacheable(value = "Item", key="#itemId", unless="#result == null")
public ItemDO findMethod1(long itemId) {
...
}
The cache works well if I call the findMethod1() directly. However, when I call findMethod2() the the cache on findMethod1() is totally ignored.
Could it be the trick made by JVM which inline the findMethod1() into findMethod2()?
Does anyone come across similar issue?
Thanks!
It's no JVM trick, i.e. findMethod1() is not being inlined inside findMethod2() or anything of that nature.
The problem is your code is bypassing the "Proxy" that Spring is creating around your application class (containing findMethod1()) for the #Cacheable annotation.
Like Spring's Transactional annotations and underlying infrastructure, given an interface, by default Spring will create a JDK Dynamic Proxy (AOP style) to "intercept" the method call and apply the "advice" (as determined by the type of annotation, in this case, caching). However, once the target object is invoked from the interceptor (Proxy) acting on behalf of the target object to apply the advice, the Thread is now executing in the context of the target object so any subsequent method invocations from within the target object are occurring directly on the target object itself.
It looks a little something like this...
caller -> Proxy -> findMethod2() -> findMethod1()
Ideally what you want is this...
caller -> Proxy -> findMethod2() -> Proxy -> findMethod1()
However, the Thread is already executing in the context of the "target" object once inside findMethod2(), so you end up with the first call stack.
The Spring doc explains it better here.
The document goes on to point out solutions to this problem, the most favorable is refactoring your code to ensure the caller is going through the Proxy interceptor for the 2nd method invocation (i.e. findMethod1()).
I also gather another solution to this problem would be to use full-blown AspectJ, using a compiler and byte-code weaver during your application build process to modify the actual target object so that subsequent invocations from within the target object intercept and apply the advice accordingly.
See the Spring docs on the trade-offs between Spring AOP and full AspectJ, as well as how to use full AspectJ in your Spring applications.
Hope this helps.
Cheers!
Other solution I find handy is using #Resource and then invoking the target (method1 in your case) using that resource reference with https://stackoverflow.com/a/48867068/2488286
Is it a best practice to wrap the ServiceStack's JsonServiceClient within a using statement?
var client = new JsonServiceClient();
client.Post(request);
versus
using (var client = new JsonServiceClient())
{
client.Post(request);
}
Which one is the best?
JsonServiceClient implements IDisposable so best practise would be to use it with a using statement.
However there are scenarios whereby you need to the share an instance of the JsonServiceClient across multiple requests (Such as when you use cookie based sessions, as the cookies are contained in the instances cookie container), in which case you would use the client without a using statement, but ensure that your application calls the Dispose method of the client, when it no longer requires the client.
This answer by gdoron further explains the best practise regarding classes that implement IDisposable such as the JsonServiceClient and the reasoning behind it.
As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement. The using statement calls the Dispose method on the object in the correct way, and (when you use it as shown earlier) it also causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and cannot be modified or reassigned.
The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler. The code example earlier expands to the following code at compile time (note the extra curly braces to create the limited scope for the object):
I hope that helps.
I might be on the wrong track here, but here goes:
In my PhoneGap Durandal app, I have a Profile View/VM which only returns data the first time it is hit - after that it checks a bool called initialised and wont hit the DB again the 2nd time. This works fine.
However after Logout, I need to invalidate the cache. I could use a message to tell the Profile VM to clear the variable (ie. invalidate the cache) but I thought perhaps there is a higher-level way of doing this in Durandal - e.g. On Logout, I tell dispose of all ViewModels in memory (there may be other Singleton objects with session specific info in them).
Advice please...
This is more of a javascript question and this is just my understanding of how javascript works.
Javascript will automatically dispose of objects that are no longer referenced through a mechanism called Garbage Collection.
Here is a good article on how Garbage Collection works. Basically it will dispose of objects that are no longer referenced in your program.
There is another method in javascript that allows you to remove objects. The delete method:
delete someobj;
Which too my knowledge is pretty much equal to someobj = undefined;
Hope this helps.
***Edit
Durandal follows the screen activator pattern for it's viewmodels. So apart of the viewmodel lifecycle it will call an activate, candeactivate, and deactivate method.
You could do your disposing in the deactivate method.
(Durandal 2.0) You could always hook into the composition life-cycle callback methods on your view-model. There are four: activate(), attached(), deactivate(), and detached(). They are called automatically by Durandal on your view-model, if they exist. In my projects, if I need a view to invalidate its cache, I hook into the deactivate() method and put the cleanup logic there. Similarly, I use the detached() method to unbind events and destroy UI widgets.
Simple example:
define(['modules/myDataService'],
function(dataservice) {
var cache;
function activate() {
return dataservice.getData().done(function(response) {
cache = response;
});
}
function deactivate() {
cache = null;
}
return {
activate: activate,
deactivate: deactivate
};
});
Source documentation: http://durandaljs.com/documentation/Hooking-Lifecycle-Callbacks/
I've implemented IDynamicObject in C# 4, return a custom MetaObject subclass that does simple property getter/setter dispatch to a Dictionary. Not rocket science.
If I do this:
dynamic foo = new DynamicFoo();
foo.Name = "Joe";
foo.Name = "Fred";
Console.WriteLine(foo.Name);
Then 'Joe' is printed to the console... the second call to the 'Name' setter is never invoked (never steps into my custom dispatcher code at all).
I know the DLR does callsite caching, but I assumed that wouldn't apply here. Anyone know what's going on?
Whatever MetaObject you're returning from (Bind)SetMember will be cached and re-used in this case. You have 2 dynamic sites doing sets. The 1st call will cache the result in an L2 cache which the 2nd site will pick up before asking you to produce a new rule.
So whatever MetaObject you're returning needs to include an expression tree that will update the value. For example it should do something like:
return new MetaObject(
Expression.AssignProperty(this.Expression, value.Expression),
Restrictions.TypeRestriction(this.Expression, this.Value.GetType());