Announcement Announcement Module
Collapse
No announcement yet.
Need help refactoring dynamic proxy use Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Need help refactoring dynamic proxy use

    Hi!

    In an application that I need to convert to Spring, JDK's dynamic proxy is used directly.

    Code:
    class InvokationHandlerImpl extends Blah
          implements java.lang.reflect.InvocationHandler
    Code:
    client = (T) Proxy.newProxyInstance(
          obj.getClassLoader(),
          new Class[] {obj.getClass()},
          new InvokationHandlerImpl(obj));
    I'd like to reuse the existing InvocationHandlerImpl, but I see no way to inject a result of a static method call, or any method call for the same matter! The answer may be in some elaborate use of generics, but it escapes me all the same.

    Thanks in advance.

  • #2
    One workaround found: MethodReplacer

    I had to modify the bean that is the target of DI to have neither setter nor attribute to hold the proxied value, but instead I replaced the getter by MethodReplacer implementation that accepts InvokationHandlerImpl mentioned before. Haven't tested it thoroughly yet (whether it is a singleton/prototype or whether it matters), but appears to dispatch messages properly.
    Code:
    <bean id="invokationHandler" class="com.blah.ServiceInvocationHandlerClient" singleton="true">
    	<constructor-arg type="java.lang.Class" value="com.blah.Service" />
    	<constructor-arg type="com.blah.ClientDelegate">
    		<bean class="com.blah.ClientDelegate" />
    	</constructor-arg>
    </bean>
    
    <bean id="proxyLookupReplacer" class="com.blah.ProxyCreationMethod">
    	<property name="invokationHandler" ref="invokationHandler" />
    </bean>
    
    <bean id="client" class="com.blah.ServiceClient">
    	<replaced-method name="getService" replacer="proxyLookupReplacer" />
    </bean>
    Don't hesitate to offer a better solution
    Last edited by denka; Jan 11th, 2007, 09:04 PM.

    Comment


    • #3
      I think your solution (very creative) will introduce a dependency on Cglib. If you don't care about that (e.g. using Hibernate already) then nevermind. But it seems more natural to use a Spring AOP proxy rather than a method replacement. It would be very similar configuration-wise but the result would be exactly as in your original, i.e. a JDK Proxy.

      Comment


      • #4
        I don't like the sound of it "very creative"? Please, could you include an example of use of Spring AOP proxy for the same?

        Comment


        • #5
          Look for the docos on ProxyFactoryBean, or aop:advice. Example sketch for the former (possibly incomplete):

          Code:
          <bean id="invokationHandler" class="com.blah.ServiceInvocationHandlerClient">
          	<constructor-arg type="java.lang.Class" value="com.blah.Service" />
          	<constructor-arg type="com.blah.ClientDelegate">
          		<bean class="com.blah.ClientDelegate" />
          	</constructor-arg>
          </bean>
          
          <bean id="proxyLookupInterceptor" class="com.blah.ProxyCreationInterceptor">
          	<property name="invokationHandler" ref="invokationHandler" />
          </bean>
          
          <bean id="client" class="org.springframework.aop.framework.ProxyFactoryBean">
              <property name="proxyInterfaces" value="com.blah.Client" />
              <property name="interceptorNames">
                  <list>
                      <value>proxyLookupInterceptor</value>
                  </list>
              </property>
              <property name="target">
                  <bean class="com.blah.ServiceClient">
              </property>
          </bean>
          Using the newer style aop:aspect config you don't even need to implement InvocationHandler (or any special interface), but since you already have that you could start with something like the above. The proxyLookupInterceptor is an adapter from InvocationHandler to MethodInterceptor.

          Comment


          • #6
            Sounds like a winner. Thank you so much! Will report back how well it works for me as soon as I can try it out.

            Comment


            • #7
              Maybe a bug or discrepancy in the JavaDoc?

              according to javadoc http://www.springframework.org/docs/...va.lang.String[])

              The referenced beans should be of type Interceptor, Advisor or Advice The last entry in the list can be the name of any bean in the factory. If it's neither an Advice nor an Advisor, a new SingletonTargetSource is added to wrap it. Such a target bean cannot be used if the "target" or "targetSource" or "targetName" property is set, in which case the "interceptorNames" array must contain only Advice/Advisor bean names.
              Code:
              <bean id="invocationHandler" class="com.blah.ServiceInvocationHandlerClient" singleton="true">
              		<constructor-arg type="java.lang.Class" value="com.blah.Service" />
              		<constructor-arg type="com.blah.ClientDelegate">
              			<bean class="com.blah.ClientDelegate" />
              		</constructor-arg>
              	</bean>
              
              	<bean id="proxyLookupInterceptor" class="com.blah.ProxyCreationInterceptor">
              		<property name="invocationHandler" ref="invocationHandler" />
              	</bean>
              
              	<bean id="client" class="org.springframework.aop.framework.ProxyFactoryBean">
              		<property name="interceptorNames" value="proxyLookupInterceptor" />
              		<property name="proxyInterfaces" value="com.blah.Service" />
              	</bean>
              As you can see, I specify an Interceptor in interceptorNames property, but no target ('cause I don't have one), in which case I expect a SingletonTargetSource would wrap my interceptor and become a target of this proxy, but this is not happening. When I inspect values of MethodInvocation in this ProxyCreationInterceptor:

              Code:
              public class ProxyCreationInterceptor<T> implements MethodInterceptor {
              	private Object cachedProxy;
              	private InvocationHandler invocationHandler;
              
              	public Object invoke(MethodInvocation mi) throws Throwable {
              		return mi.getMethod().invoke(
              			getProxy(mi.getThis().getClass(), mi.getThis()),
              			mi.getArguments());
              	}
              
              	public void setInvocationHandler(InvocationHandler ih) {
              		invocationHandler = ih;
              	}
              
              	private synchronized Object getProxy(Class clazz, Object target) {
              		if (cachedProxy == null) {
              			cachedProxy = Proxy.newProxyInstance(
              				clazz.getClassLoader(), new Class[]{clazz}, invocationHandler);
              		}
              
              		return cachedProxy;
              	}
              }
              mi.getThis() returns null, since this is what my ProxyFactoryBean ends up holding as its target.

              Is this a bug? Any workarounds possible?

              Comment


              • #8
                ...and a workaround was not far off Once I refrained from using MethodInvocation.getThis() to acquire class (since it's completely unneccessary), I made it to work. I have to supply the target class to my
                Code:
                public class ProxyCreationInterceptor<T> implements MethodInterceptor
                instead.

                Thanks much for your help in guiding me towards solution!

                Comment

                Working...
                X