I am using the ProxyFactory to create a proxy with a list of method interceptors. One of these interceptors needs to access an object (in its invoke() method) that exists in the context of the caller of the ProxyFactory. How can I make it available to this interceptor ?
The cleanest way, in my opinion, would be to set this object in the method invocation object itself (by using the userAttributes map of ReflectiveMethodInvocation), but I do not have access to that object while it is being created.
There are other directions for doing this, but I don't like them :
- the client of ProxyFactory sets this object in a ThreadLocal, and the interceptor gets it back and uses it. This is certainely not beautiful, but the main problem is that I do not have the opportunity to clean the ThreadLocal after invocation (except by telling my users to do it).
- When the client code iterates over the list of advices (in order to add them to the ProxyFactory), I test if this is my interceptor, and inject the object into it. The problem is that I will set a dependency on this interceptor in the client code, and, -more serious- as this interceptor is a singleton in my application context, I need to clone it before setting the object and adding it as an advice to the ProxyFactory (or set this interceptor as a prototype in my application context).
Setting it in the method invocation would need the following rewrite of some Spring classes :
client code:
The additional method (setMethodInvocationUserAttribute()) is defined on AdvisedSupport, and maps to a userAttributes map; the JdkDynamicAopProxy.invoke() is changed as follows (line 202 in release 2.0.6):Code:ProxyFactory pf = new ProxyFactory(); pf.setMethodInvocationUserAttribute("my.context", ctx); for (Advice a:advicesList) { pf.addAdvice(a); } pf.setTarget(target); Object decorated = pf.getProxy();
Doing this, an interceptor can simply access this object in its invoke method :Code:invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); Map userAttributes = this.advised.getMethodInvocationUserAttributes(); for (String key: userAttributes.keySet()) { invocation.setUserAttribute(key, userAttributes.get(key); } // line 203 follows
Isn't that exactly what this userAttributes Map in ReflectiveMethodInvocation was supposed to be used to ?Code:public Object invoke(MethodInvocation mi) throws Throwable { Map context = ((ReflectiveMethodInvocation) mi).getUserAttributes(); // play with it }
Of course, I do not have the complete map of Spring AOP framework in mind, but it sounds to me that it's the most elegant way.
To be more precise, the situation is as follows :
- the client code is an AbstractStatelessSessionBean which goal is to wrap a POJO service with the same business interface as the EJB
- there are common method interceptors that must wrap each POJO service call that is accessed via EJB; developers create an EJB, and delegate each method call to the proxied POJO service, loaded, decorated and set as an instance variable in onEjbCreate(). The interceptors are configured in an application context
- one of these interceptor needs to access the EJBContext.


Reply With Quote

