问题
I have a DAO that has some methods that make queries to a database using org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
. Few of this methods have certain method arguments and I would like to capture database queries made from these methods. I would like to write an AOP that would capture the SQL queries made from these methods along with the value of the argument. Below is one of the methods(that I need to capture) that makes jdbc query:
My 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);
I need an AOP solution that would capture finalQuery
and columnMap
.
Is that even possible in AOP. Do you have any other solutions?
I tried to write below aspect but I am able to only capture finalQuery
but not 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 {
//......
}
Thanks in Advance
回答1:
Okay, just in order to make you understand what an MCVE is and how easy it is to provide one if you only want, I made one for you. Actually this was your job! Next time do it by yourself, please.
Your incoherent snippets do not tell me which classes to import, how variables like namedParameterJdbcTemplate
are defined and initialised, how your Spring Boot is configured and many more things. So I had to make educated guesses and create dummy classes just so as to recreate your situation and test my own solution. Untested solutions are cr*p and so is a question forcing me to do that kind of guesswork in the first place.
What you want to implement is the wormhole pattern, see also my answers here and here, both in AspectJ native syntax. The one I prepared for you is in the annotation-based syntax I so dislike, but which you seem to prefer for whatever reason.
Dummy helper classes:
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 + "]";
}
}
Driver application:
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);
}
}
Aspect implementing wormhole pattern:
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);
}
}
Console log:
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
Now, Amit, what the heck was so difficult for you about providing a little example for your SO helpers' benefit, so they don't have to do your own job for free in their spare time? Just picking up and fixing your own MCVE would have been so much easier and definitely not asking too much of the experienced developer you seem to think you are. This sense of entitlement - "Developers here have nothing better to do than create a running example for themselves because I am too lazy." - I just don't get it. Who are you? A king?
来源:https://stackoverflow.com/questions/50551816/is-it-possible-to-intercept-arguments-of-a-method-call-and-method-inside-which-t