【问题标题】:Spring AOP - proxying object returned from methodSpring AOP - 从方法返回的代理对象
【发布时间】:2017-05-15 15:33:02
【问题描述】:

在这个例子中:

public class ConnectionPool {
  public java.sql.Connection getConnection() {
      ...
  }
}

@Bean
@Scope("singleton")
public ConnectionPool connectionPool(...) throws Exception {
    return new ConnectionPoolImpl(...);
}

我想监控从 getConnection() 返回的 Connection 对象上对 java.sql.Connection.close() 的调用。

我尝试在 getConnection() 方法中添加@Lookup,但没有效果。

如何让 Spring 代理 java.sql.Connection 对象?

【问题讨论】:

  • 监控并做什么?
  • 像添加切入点一样监控。我正在编写一个泄漏检测器,它将在每个 HTTP 请求之后检查所有连接是否都返回到池中。
  • 这不是 Spring 可以单独完成的事情,假设 getConnection 返回由您的代码管理的 Connection 对象。您需要使用@AfterReturning@Around 建议拦截getConnection。然后,您需要实现该建议以包装在某个委托对象(或构建代理)中返回的 Connection 对象,仅拦截其 close 方法并进行检测。

标签: java spring spring-aop


【解决方案1】:

可以为ConnectionPool创建代理,并在bean创建方法中返回代理

@Bean
@Scope("singleton")
public ConnectionPool connectionPool(...) throws Exception {
    ConnectionPoolImpl delegate = new ConnectionPoolImpl(...);
    ConnectionPoolCallHandler callHandler = new ConnectionPoolCallHandler(delegate);
    ConnectionPool proxy = Proxy.newProxyInstance(
                ConnectionPool.getClass().getClassLoader(),
                new Class[]{ConnectionPool.class},
                callHandler);

//    return new ConnectionPoolImpl(...);
    return proxy;
}

public class ConnectionPoolCallHandler implements InvocationHandler {
    private ConnectionPoolImpl delegate;
    public ConnectionPoolCallHandler(ConnectionPoolImpl delegate) {
        this.delegate=delegate;
    }
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
         //all invoked methods should call 
         //appropriate methods of delegate passing all parameters
         //plus your additional tracking logic here
    }
}

【讨论】:

    【解决方案2】:
    @Pointcut("within(java.sql.Connection.close(..)")
    public void closeAspect() {}
    
    @Around("closeAspect()")
    public void logAround(ProceedingJoinPoint joinPoint) throws Throwable 
    {
      joinPoint.getThis();//Will return the object on which it(close function) is called 
      //Do whatever you want to do here
       joinPoint.proceed();   
      //Do whatever you want to do here
    }
    

    【讨论】:

    • 您假设 Connection 对象由 Spring 管理(因此可以被代理)。你能否说得更清楚一些并解释你为什么做出这样的假设?
    • 你是对的,如果连接对象不是由 spring 管理的,那么这段代码将不起作用。但考虑到问题中没有明确提到它不是弹簧管理的 bean 并且还查看用于该问题的标签这一事实,我相信这是一个票价假设。
    最近更新 更多