如何通过Java中的反射调用代理方法(Spring AOP)?

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不会调用.

Mar*_*olt 5

正如您所注意到的,您无法在 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。


Fre*_*ula 1

您必须从代理的类中调用该方法。尝试这个:

manager.getClass().getMethod("read", Long.class).invoke(manager, 1L);