SyntaxHighlighter

Friday, August 31, 2012

Accessing Spring Proxies - Reflection and Advised


Accessing Spring Proxies - Reflection and Advised


a reoccuring issue that i've struck when using Spring is trying to work with a proxied object in reflection.  it's not something that occurs all the time, and there's very smart people doing very smart things with this, but here's what i've found works… Advised

basically, when you retrieve an object that's been proxied by Spring, it can be cast to an Advised object that can then be used to retrieve the underlying object.  

if you execute the underlying object though, you don't get the advantage of whatever aspect you had added so beware of that.

in any event, here's the code to get a quick sample up and running.

here's our holder

package org.incompletecode.proxy;
public class ProxyHolder {
private ProxiedClass proxiedClass;
public void useProxiedClass() {
proxiedClass.doSomething();
}
public void setProxiedClass(ProxiedClass proxiedClass) {
this.proxiedClass = proxiedClass;
}
}
view raw gistfile1.java hosted with ❤ by GitHub


here's the proxied class

package org.incompletecode.proxy;
public class ProxiedClass {
public void doSomething() {
System.out.println("hello world");
}
}
view raw gistfile1.java hosted with ❤ by GitHub


here's our aspect

package org.incompletecode.proxy.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class ProxiedClassAspect {
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//add something to the visibility
System.out.println("before executing...");
Object result = proceedingJoinPoint.proceed();//let it continue
System.out.println("... after executing");
//carry on
return result;
}
}
view raw gistfile1.java hosted with ❤ by GitHub


and here's our context XML

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<aop:config>
<aop:aspect ref="proxiedClassAspect">
<aop:around method="around" pointcut-ref="aroundRef"/>
<aop:pointcut expression="execution(* org.incompletecode.proxy.ProxiedClass.doSomething())" id="aroundRef"/>
</aop:aspect>
</aop:config>
<bean id="proxyHolder"
class="org.incompletecode.proxy.ProxyHolder">
<property name="proxiedClass" ref="proxiedClass"/>
</bean>
<bean id="proxiedClass"
class="org.incompletecode.proxy.ProxiedClass">
</bean>
<bean id="proxiedClassAspect"
class="org.incompletecode.proxy.aspect.ProxiedClassAspect">
</bean>
</beans>
view raw gistfile1.xml hosted with ❤ by GitHub


now, finally, the test that shows what can be done

package org.incompletecode.proxy;
import java.lang.reflect.Field;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:/META-INF/spring/application-context.xml"})
public class ProxyHolderTest {
@Autowired
private ProxyHolder holder;
@Test
public void test() throws Exception {
//lets do a plain run first
holder.useProxiedClass();
//now lets use reflection to retrieve the object
for (Field field : holder.getClass().getDeclaredFields()) {
if (field.getType().equals(ProxiedClass.class)) {
//got our field, lets get the object
field.setAccessible(true);
//show it first to see that it's proxied
Object object = field.get(holder);
System.out.println(object.getClass().getName());
//now cast to get the underlying object
ProxiedClass proxiedClass = (ProxiedClass)((Advised)object).getTargetSource().getTarget();
System.out.println(proxiedClass.getClass().getName());
//now execute directly
proxiedClass.doSomething();
}
}
}
}
view raw gistfile1.java hosted with ❤ by GitHub


No comments:

Post a Comment