Rad*_*don 6 java reflection proxy spring method-invocation
界面:
public interface Manager {
Object read(Long id);
}
Run Code Online (Sandbox Code Playgroud)
实现此接口的类:
@Transactional
Public class ManagerImpl implements Manager {
@Override
public Object read(Long id) {
// Implementation here
}
}
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
控制器:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
因此,当spring在控制器代理中创建时注入manager变量.
直接调用方法时:
manager.read(1L)
Run Code Online (Sandbox Code Playgroud)
方面被调用.
但是,当我尝试这样做时(参见readViaReflection)
ManagerImpl.class.getMethod("read", Long.class).invoke(manager, 1L);
Run Code Online (Sandbox Code Playgroud)
得到java.lang.reflect.InvocationTargetException对象不是声明类的一个实例.
这是合理的.
问题是:如何通过对spring创建的代理对象的反射来调用方法(我从target-object中提取了方法,并且我有spring创建的代理实例).
无法对目标进行调用,因为那时aspect不会调用.
正如您所注意到的,您无法在 Bean 上调用 ManagerImpl 的方法,因为 Bean 实际上是由 Proxy 实现的。
对我来说,解决方案是获取代理的调用处理程序并调用该方法。
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);
Run Code Online (Sandbox Code Playgroud)
else当 Bean 不是代理而是裸ManagerImpl类或 CGLib 代理类(在您的情况下是子类)时,该部分是必需的ManagerImpl。
您必须从代理的类中调用该方法。尝试这个:
manager.getClass().getMethod("read", Long.class).invoke(manager, 1L);