是否可以拦截方法调用的参数和进行方法调用的方法:AOP

Posted

技术标签:

【中文标题】是否可以拦截方法调用的参数和进行方法调用的方法:AOP【英文标题】:Is it possible to intercept arguments of a method call and method inside which the method call is made : AOP 【发布时间】:2018-05-27 11:48:13 【问题描述】:

我有一个 DAO,它有一些使用 org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate 对数据库进行查询的方法。这些方法中很少有特定的方法参数,我想捕获从这些方法进行的数据库查询。我想编写一个 AOP 来捕获从这些方法进行的 SQL 查询以及参数的值。以下是进行 jdbc 查询的方法之一(我需要捕获): 我的 DAO-

public List<Map<String, Object>> getData(RequestParameters requestParameter, Map<String, Column> columnMap) 
    Map<String, Object> params = new HashMap<>();
    StringBuilder finalQuery = new StringBuilder();
    finalQuery.append(getDataQuery(requestParameter, columnMap, params));
    return namedParameterJdbcTemplate.queryForList(finalQuery.toString(), params);

我需要一个能够捕获finalQuerycolumnMap 的AOP 解决方案。 这在 AOP 中是否可能。您还有其他解决方案吗?

我试图在下面写,但我只能捕捉到finalQuery 而不是columnMap

@Pointcut("withincode(public * com.abc.xyz..*.*(com.abc.xyz.RequestParameters, java.util.Map))")
private void anyGetDataMethodSignature() 
    // pointcut


@Pointcut("(call(* org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations.query*(..)) && within(com.abc.xyz.services..*.*))")
public void anyJDBCOperations() 


@Before("anyJDBCOperations() && anyGetDataMethodSignature()")
public void log(JoinPoint jp) throws Throwable 
//......

提前致谢

【问题讨论】:

您真的认为您可以删除被搁置的旧问题并将内容复制到新问题中吗?当我第三次尝试更详细地向您解释您应该提供哪些其他信息以使回答成为可能时,突然other question 被标记为“作者已删除”。但是我还是看出来了,还是有证据证明你就是拒绝按规矩办事。真丢脸! 你是认真的吗?我同意我最初的问题不清楚,但即使在更正了我的问题(当前版本)之后,它仍然被搁置。我认为这个问题对我所针对的听众来说是很清楚的。我删除了上一个问题,因为它被搁置并且不会接触到观众。你想玩同样的游戏吗?你这人怎么回事?我正在努力寻找我的问题的答案,因此,如果您不打算提供帮助,请不要发表评论和误导他人。 我是认真的,确实。听着,你是新来的,我明白。但是有关于SO的规则。禁止仅删除和重新创建暂停的问题。相反,只需改进现有问题。其他人,但你最终会决定什么时候问题已经改进到足以重新打开。我已经向您解释过,我没有将其搁置,但多个用户的投票已搁置。我还告诉你提供一个MCVE,你拒绝这样做。问题仍然由不连贯的代码 sn-ps 组成。 (待续) 您的目标受众是具有 Spring AOP 或 AspectJ 知识的 Java 开发人员。我恰好是其中之一。为了让 AOP 工作,您需要结合 Java + 方面代码 + 配置。问题可能出在其中任何一个上。诸如切入点中错误或拼写错误的包名称、缺少类注释等细微问题可能是您的问题的原因。所以请提供完整的课程,包括。包名加上 Spring 配置。目前我们只有 sn-ps - 一个好的开始,但还不足以回答这个问题,抱歉。 (待续) 然后,尤其是在 Spring 中,您可以使用两种类型的 AOP:基于代理的 Spring AOP 和通过 LTW(加载时编织)的完整 AspectJ。没有任何配置,我看不到您使用的是哪一个。在另一个问题中,您还评论了:“没有可重现的代码,我在这里寻求解决方案。我认为任何具有 java 背景的人都会得到我想要问的。” 这两个陈述都是false:当然,您可以将问题提炼为 MCVE。而且理解Java并不等于理解AOP。明明你自己有Java背景,但也不懂吧? 【参考方案1】:

好的,只是为了让您了解MCVE 是什么以及如果您只想提供一个是多么容易,我为您制作了一个。其实这是你的工作!下次请自己做。

你语无伦次的 sn-ps 没有告诉我要导入哪些类,如何定义和初始化像 namedParameterJdbcTemplate 这样的变量,如何配置 Spring Boot 以及更多其他事情。所以我不得不做出有根据的猜测并创建虚拟类,以便重现您的情况并测试我自己的解决方案。未经测试的解决方案是 cr*p,所以一个问题迫使我首先进行这种猜测。

您要实现的是 虫洞模式,另请参阅我的答案 here 和 here,均采用 AspectJ 原生语法。我为你准备的那个是我非常不喜欢的基于注释的语法,但无论出于何种原因你似乎更喜欢它。

虚拟助手类:

package de.scrum_master.app;

public class RequestParameters 
package de.scrum_master.app;

import java.util.List;
import java.util.Map;

public class DummyJdbcTemplate 
  public List<Map<String, Object>> queryForList(String string, Map<String, Object> params) 
    return null;
  

package de.scrum_master.app;

public class Column 
  private String columnType;

  public Column(String columnType) 
    this.columnType = columnType;
  

  @Override
  public String toString() 
    return "Column[columnType=" + columnType + "]";
  

驱动程序应用:

package de.scrum_master.app;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Application 
  private DummyJdbcTemplate namedParameterJdbcTemplate = new DummyJdbcTemplate();

  public List<Map<String, Object>> getData(RequestParameters requestParameter, Map<String, Column> columnMap) 
    Map<String, Object> params = new HashMap<>();
    StringBuilder finalQuery = new StringBuilder();
    finalQuery.append(getDataQuery(requestParameter, columnMap, params));
    return namedParameterJdbcTemplate.queryForList(finalQuery.toString(), params);
  

  public String getDataQuery(RequestParameters requestParameter, Map<String, Column> columnMap, Map<String, Object> params) 
    return "I am the final query";
  

  public static void main(String[] args) 
    HashMap<String, Column> columnMap = new HashMap<>();
    columnMap.put("id", new Column("Long"));
    columnMap.put("name", new Column("VarChar"));
    columnMap.put("age", new Column("Int"));
    new Application().getData(new RequestParameters(), columnMap);
  

实现虫洞模式的方面:

package de.scrum_master.aspect;

import java.util.Map;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import de.scrum_master.app.Column;

@Aspect
public class MyAspect 
  @Pointcut(
    "execution(public * de.scrum_master.app..*(..)) && " +
    "args(de.scrum_master.app.RequestParameters, columns)"
  )
  private void anyGetDataMethodSignature(Map<String, Column> columns) 

  @Pointcut(
    "call(* de.scrum_master.app.DummyJdbcTemplate.query*(..)) && " +
    "args(query, ..)"
  )
  private void anyJDBCOperations(String query) 

  @Before(
    "anyJDBCOperations(query) &&" +
    "cflow(anyGetDataMethodSignature(columns))"
  )
  public void log(JoinPoint thisJoinPoint, Map<String, Column> columns, String query) throws Throwable 
    System.out.println(thisJoinPoint);
    System.out.println("  columns = " + columns);
    System.out.println("  query = " + query);
  

控制台日志:

call(List de.scrum_master.app.DummyJdbcTemplate.queryForList(String, Map))
  columns = name=Column[columnType=VarChar], id=Column[columnType=Long], age=Column[columnType=Int]
  query = I am the final query

现在,Amit,为 SO 助手的利益提供一个小例子,让他们不必在业余时间免费做你自己的工作,这对你来说到底是什么困难?只需拿起并修复您自己的 MCVE 就会容易得多,而且绝对不会对您似乎认为自己是的经验丰富的开发人员提出太多要求。这种权利感——“这里的开发人员没有什么比为自己创建一个运行示例更好的事情了,因为我太懒了。” - 我就是不明白。你是谁?国王?

【讨论】:

看,阿米特,这里是another SO newbie with AOP problems。他一开始也没有提供 MCVE,然后按照我的建议更新了他的问题。十分钟后,他从我这里得到了解决方案。你浪费了几天,仍然没有这样做。你怎么这么固执?您对快速解决问题不感兴趣吗?善待他人,尤其是那些你希望得到帮助的人。他们很有可能也会对你很好。

以上是关于是否可以拦截方法调用的参数和进行方法调用的方法:AOP的主要内容,如果未能解决你的问题,请参考以下文章

Spring AOP不拦截从对象内部调用的方法原因

dubbo中拦截生产者或消费者服务方法调用

拦截方法调用

Spring AOP 是不是可以拦截 线程内部调用的拦截方法?

Spring AOP不拦截从对象内部调用的方法原因

Spring AOP不拦截从对象内部调用的方法原因