I have this object:
@Service
public class myBr {
@PostFilter("filterObject.cellule.getId()==2")
public List<Bibliotheque> getB() {
return super.getAll();
}
public List<Bibliotheque> get开发者_如何学PythonA() {
return getB();
}
}
When I call from a test that does myBr.getB()
, the @PostFilter
is applied, but when I call myBr.getA()
, the postfilter is not working.
Is there a way to handle this so that the filter is applied?
The issue is that the @PostFilter
is applied through AOP techniques, yet you are calling the instance's implementation of getB()
directly from getA()
, and Spring AOP does not rewrite classes.
Here's what's going on:
+————————+ +——————————+
getA | pass | getA | |
—————>|·······>|—————>| |———+
| | | | |
| Bean | | Instance | | this.getB
| | | | |
getB | filter | getB | | |
—————>|·······>|—————>| |<——+
| | | |
+————————+ +——————————+
Spring AOP puts a proxy object as the actual bean that delegates to your bean, either by using a JDK proxy object (when you've got a suitable interface) or by using CGLIB to synthesize the object de novo. For getA
it just passes straight through, and for getB
it inserts the call into the post filtering code. That's great, but it does mean that when the instance — the object you've got as this
inside the getA
— is used to invoke getB
directly, it skips the filter and jumps straight into the underlying code.
There are four possible fixes.
- Use AspectJ to do the application of the AOP code, which does code rewriting (at a cost of a lot more complexity in deployment).
- Give a handle to the bean to the instance (has to be done explicitly; you can't autowire it) and invoke
getB
through that. - Put
getB
in a different bean. - Put the filtering on both methods.
I've used option #2 myself (it was easier than the alternatives in my particular situation) and it works quite well, but the best option is almost certainly #3, so that you don't need to do self-calls to “interface” methods; that sort of thing is often indicative of incorrect partitioning of the application's functionality.
I assume that you have already solved your problem, but in case anyone is wondering about similar stuff with his bean calls (i had the same problem with EJBs): Method annotations are read by the container/the application context or whatever it is that handles the injection. And when, like in this case, some kind of interceptor is needed to trigger the expected behaviour, it works only for calls from 'outside' of a bean, that is, the proxy object wrapped around your bean. What getA() does in this case is a local call, so technically your thread jumps directly to method getB(), but it doesn't regard any annotations at all.
I think the only possible solution I can think of is to also add a @PostFilter annotation to the getA method. This is because annotations works by creating a proxy object around the class instance there for adding and advice that handles the expressions (in this case after the method has been called) This is a aspect oriented trick but when you call a method from within the same instance the advice that was created is never called, that's why it doesn't work that way.
精彩评论