8

一个接口:

public interface Manager {
  Object read(Long id);
}

实现此接口的类:

@Transactional
Public class ManagerImpl implements Manager {
  @Override  
  public Object read(Long id) {
    //  Implementation here  
  }
}

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();
  }
}

控制器:

@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);
  }
}

因此,当 spring 在创建的控制器代理中注入 manager 变量时。
直接调用方法时:

manager.read(1L)  

方面被调用。

但是,当我尝试这样做时(请参阅readViaReflection

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

得到java.lang.reflect.InvocationTargetException对象不是声明类的实例。
这是合理的。

问题是:如何通过spring创建的代理对象的反射调用方法(我有从目标对象中提取的方法,并且我有spring创建的代理实例)。

不能对目标进行调用,因为这样就不会调用方面。

4

4 回答 4

4

正如您所注意到的,您不能在 bean 上调用 ManagerImpl 的方法,因为 Bean 实际上是由 Proxy 实现的。

对我来说,解决方案是获取 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);

else当 Bean 不是代理,而是裸ManagerImpl类或 CGLib 代理类(ManagerImpl在您的情况下为子类)时,该部分是必需的。

于 2017-10-13T09:45:48.740 回答
1

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

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

于 2015-07-20T14:51:03.650 回答
0

我不认为java反射会做这个行程,你需要使用 if() 切入点表达式

要实现它,您可以定义另一个布尔参数(名为 invokeAOP),当您manager使用 invokeAOP = true 调用时,您将执行您的 Aspect。否则,您的 Aspect 将被省略。

于 2015-07-20T15:11:37.923 回答
0

您可以在不使用反射的情况下做到这一点 - 它只需要一些转换:

((Manager) ((Advised)manager).getTargetSource().getTarget()).read(1L);

很酷的是它可以与 JDK 和 CGLIB 代理一起使用。

如果您必须使用反射,请使用此解决方案的一部分:

Manager managerBean = ((Manager) ((Advised)manager).getTargetSource().getTarget()); managerBean.getClass().getMethod("read", Long.class).invoke(managerBean, id)

于 2015-07-20T15:34:12.237 回答