An interface:
public interface Manager {
Object read(Long id);
}
A class which implements this interface:
@Transactional
Public class ManagerImpl implements Manager {
@Override
public Object read(Long id) {
// Implementation here
}
}
An aspect for ManagerImpl:
@Aspect
public class Interceptor {
@Pointcut("execution(public * manager.impl.*.*(..))")
public void executionAsManager() {
}
@Around("executionAsManager()")
public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
// Do some actions
return joinPoint.proceed();
}
}
A controller:
@RestController()
public class Controller {
@Autowired
private Manager manager;
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Object read(@PathVariable Long id) {
return manager.read(id);
}
@RequestMapping(value = "reflection/{id}", method = RequestMethod.GET)
public Object readViaReflection(@PathVariable Long id) {
return ManagerImpl.class.getMethod("read", Long.class).invoke(manager, id);
}
}
So, when spring injects manager variable within controller proxy created.
When method invoked directly:
manager.read(1L)
aspect is invoked.
However, when I try to do like this (see readViaReflection)
ManagerImpl.class.getMethod("read", Long.class).invoke(manager, 1L);
got java.lang.reflect.InvocationTargetException object is not an instance of declaring class.
Which is reasonable.
The question is: how can I invoke method via reflection on proxy-object created by spring (I have method extracted from target-object and I have instance of proxy created by spring).
Can not do invocation on target because then aspect will not invoke.
As you have noticed, you cannot invoke the method of ManagerImpl on the bean, beacause the Bean is actually implemented by a Proxy.
For me, the solution was to get the invocation handler of the Proxy and call the method.
if (Proxy.isProxyClass(manager.getClass())) {
Method readMethod = ManagerImpl.class.getMethod("read", Long.class);
Proxy.getInvocationHandler(manager).invoke(manager, readMethod, parameter);
} else
info.getMethod().invoke(serviceClass, parameter);
The else
part is necessary when the Bean is not a Proxy, but either the bare ManagerImpl
class or a CGLib proxy class (which would subclass ManagerImpl
in your case).
You must invoke the method from the proxy's class. Try this:
manager.getClass().getMethod("read", Long.class).invoke(manager, 1L);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With