***************************************分割线******************************************************

参考:https://bbs.csdn.net/topics/390556755

两位老哥的回复。

想着在service层再单独写个方法去调用mapper;

  public int updateOrderStatus(Map param){
log.info("updateOrderStatus==============="+param+"======================");
return rechargeMapper.updateOrderStatus(param);
}
int uptNum = this.updateOrderStatus(orderMap);

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

所以重新包装一下mapper类,新建一个类

@Service
public class RechargeServiceAop {
private org.slf4j.Logger log = LoggerFactory.getLogger(String.valueOf(RechargeServiceAop.class));
@Autowired
private RechargeMapper rechargeMapper; public int updateOrderStatus(Map param){
log.info("updateOrderStatus==============="+param+"======================");
return rechargeMapper.updateOrderStatus(param);
}
}

将业务层调用mapper的方法改为调用新的实现类

 int uptNum = rechargeServiceAop.updateOrderStatus(orderMap);

然后去切这个新的类方法

  @After("execution(public * com.zhx.recharge.service.RechargeServiceAop.updateOrderStatus(..))")

***************************************分割线******************************************************

之前引用的博客方法在junit本地测试可用,但是更新上服务器不可用。

***************************************分割线******************************************************

https://blog.csdn.net/weixin_35562755/article/details/78689862?utm_source=copy

以下为项目dao层的简单接口定义:

public interface BaseDao {

public List<List<String>> queryListData(String sql, Object[] o);

public List<List<String>> queryListDataNoParams(String sql);

public List queryList(String sql, Object[] o);

public <T> List<T> queryObjList(String sql, Object[] args, Class<T> clazz);

public int queryForInt(String sql, Object[] o);

public int addOrUpdate(String sql, Object[] o);
}

可以发现传参比较简单,基本都是传入sql,以及一些sql参数,我们只需要拦截到这些要执行的方法,通过JAVA反射拿到对应的参数,进行控制台输出就好了。但是仅仅输出了sql还不够,我们还需要显示的知道这个方法的调用过程。这里通过Java线程来获取方法运行栈的信息。对比看了下具有sql监控的淘宝数据源druid,其实现逻辑大体上也是运用了AOP的原理进行SQL的监控。

废话不少说直接上代码:
1)自定义一个方法拦截器 DisplayExecuteSqlInterceptor :

package com.XXX.CCC.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.lang.reflect.Method; /**
*
* 方法拦截 粒度在方法上
*
* @desc 调试管理 利用 AOP 原理, 在开发模式下于控制台展示 dao层 的实际执行的SQL
* 粘出来即可 在pl/sql下执行,已经替换掉 ? 了
*
* @author luotianyi
* @create 2017-11-30 14:03
**/
public class DisplayExecuteSqlInterceptor implements MethodInterceptor { private static final Logger log = LoggerFactory.getLogger(DisplayExecuteSqlInterceptor.class); private static final String CONTROLLER ="CONTROLLER";
private static final String SERVICE ="SERVICE";
private static final String DAO ="DAO";
private static final String IMPL ="IMPL"; @Override
public Object invoke(MethodInvocation mi) throws Throwable { //系统的开发模式
String codeModel =System.getProperty("codeModel");
String flag="true";
if(StringUtils.equals(flag,codeModel)){
//获取该方法的传参
Object[] ars = mi.getArguments(); //通过反射机制 获取到该方法 (Method 包含 作用域 返回类型 方法名 参数类型)
Method method= mi.getMethod(); //获取代理的对象 (也就是这个方法所在内存中的对象)
Object obj = mi.getThis(); Object [] params =new Object[]{} ;
String sql ="";
for(Object o :ars){
if(o instanceof Object[]){
params= (Object[]) o;
}else if(o instanceof String){
sql=(String) o;
}
} Thread current = Thread.currentThread();
StackTraceElement[] elements =current.getStackTrace(); //倒序输出 栈帧 信息 ,过滤出 项目的代码 这里只过滤出(Controller / service impl / dao impl)层的代码,如需要其他的可自行遍历
if(elements !=null && elements.length>0){
//获得项目名
String packageName =DisplayExecuteSqlInterceptor.class.getPackage().getName();
packageName=StringUtils.substringBefore(packageName,".");
StringBuilder sb =new StringBuilder();
sb.append(" -------->本次执行SQL的代码在<--------- ");
sb.append('\n');
for(int i=elements.length ;i>0 ;i--){
StackTraceElement e =elements[i-1];
if(StringUtils.contains(e.getClassName(),packageName)){
String cn=StringUtils.upperCase(e.getClassName());
if(StringUtils.contains(cn,CONTROLLER)){
sb.append( CONTROLLER+" 层 ->类名:"+e.getClassName()+",方法名:"+e.getMethodName()+",代码行数:"+e.getLineNumber()+"");
sb.append('\n');
}else if(StringUtils.contains(cn,SERVICE) &&StringUtils.contains(cn,IMPL) && e.getLineNumber()>0) {
sb.append( SERVICE+" 层 ->类名:"+e.getClassName()+",方法名:"+e.getMethodName()+",代码行数:"+e.getLineNumber()+"");
sb.append('\n');
}else if(StringUtils.contains(cn,DAO) &&StringUtils.contains(cn,IMPL) && e.getLineNumber()>0 ){
sb.append(DAO +" 层->类名:"+e.getClassName()+",方法名:"+e.getMethodName()+",代码行数:"+e.getLineNumber()+"");
sb.append('\n');
}
}
}
log.info(sb.toString());
}
getExecuteSql(sql,params);
}
//执行被拦截的方法,切记,如果此方法不调用,则被拦截的方法不会被执行。
return mi.proceed();
} private String getExecuteSql(String sql, Object[] params) {
if (StringUtils.isNotBlank(sql)) {
if (params != null && params.length > 0) {
int a = getCount(sql, '?');
int b = params.length;
if (a == b) {
sql = StringUtils.replace(sql, "?", "XXXX");
for (int i = 0; i < params.length; i++) {
Object obj = params[i];
if (StringUtils.isNotBlank(String.valueOf(obj)) && StringUtils.isNumeric(String.valueOf(obj))) {
obj = Integer.valueOf(String.valueOf(obj));
} else {
obj = "'" + obj + "'";
}
sql = sql.replaceFirst("XXXX", String.valueOf(obj));
}
} else {
log.info("参数个数传的不正确, sql中 需要 :{} 个参数,实际传入参数为 :{} 个。", a, b);
return null;
}
}
} StringBuilder sb =new StringBuilder();
sb.append(" ----------->本次执行sql为:<----------- ");
sb.append('\n');
sb.append(sql+'\n'); log.info(sb.toString());
return sql; } private int getCount(String sql ,char a ){
int count=0;
if(StringUtils.isNotBlank(sql)){
for (int i = 0; i < sql.length(); i++) {
if(sql.charAt(i)==a){
count++;
}
}
}
return count;
} }

2)在spring配置文件中,添加下一下的配置:

<bean id="displayExecuteSqlInterceptor" class="com.zhx.base.interceptor.DisplayExecuteSqlInterceptor" ></bean>
<!--将自定义拦截器注入到spring中-->
<aop:config> <!--切入点,也就是你要监控哪些类下的方法,由于是监控SQL的执行情况,这里写的是DAO层的目录,包名要记得换成你自己项目的目录哟,大兄弟-->
<aop:pointcut id="displayExecuteSql" expression="execution(public * com. com.XXX.CCC.base.dao.impl.*.*(..)) "/>
<!--在该切入点使用自定义拦截器-->
<aop:advisor pointcut-ref="displayExecuteSql" advice-ref="displayExecuteSqlInterceptor"/> </aop:config>

aop切入mapper接口的更多相关文章

  1. 由一个RABBITMQ监听器死循环引出的SPRING中BEAN和MAPPER接口的注入问题

    1 @Slf4j 2 @RestController 3 @Component 4 public class VouchersReceiverController implements Message ...

  2. Spring AOP在函数接口调用性能分析及其日志处理方面的应用

    面向切面编程可以实现在不修改原来代码的情况下,增加我们所需的业务处理逻辑,比如:添加日志.本文AOP实例是基于Aspect Around注解实现的,我们需要在调用API函数的时候,统计函数调用的具体信 ...

  3. Mybatis的mapper接口接受的参数类型

    最近项目用到了Mybatis,学一下记下来. Mybatis的Mapper文件中的select.insert.update.delete元素中有一个parameterType属性,用于对应的mappe ...

  4. MyBatis Mapper 接口如何通过JDK动态代理来包装SqlSession 源码分析

    我们以往使用ibatis或者mybatis 都是以这种方式调用XML当中定义的CRUD标签来执行SQL 比如这样 <?xml version="1.0" encoding=& ...

  5. mybatis的基本配置:实体类、配置文件、映射文件、工具类 、mapper接口

    搭建项目 一:lib(关于框架的jar包和数据库驱动的jar包) 1,第一步:先把mybatis的核心类库放进lib里

  6. Mybatis源码解析-MapperRegistry注册mapper接口

    知识储备 SqlsessionFactory-mybatis持久层操作数据的根本,具体的解析是通过SqlSessionFactoryBean生成的,具体的形成可见>>>Spring ...

  7. mybatis 详解(六)------通过mapper接口加载映射文件

    通过 mapper 接口加载映射文件,这对于后面 ssm三大框架 的整合是非常重要的.那么什么是通过 mapper 接口加载映射文件呢? 我们首先看以前的做法,在全局配置文件 mybatis-conf ...

  8. Mybatis中是否需要依赖配置文件的名称要和mapper接口的名称一致 params错误

    一:当核心配置文件mapper标签下以resource形式指向依赖配置文件时,不需要 这样就可以加载到其相应的依赖配置文件通过namespace找到其相应的方法 二:如果mapper标签下以packa ...

  9. MyBatis-Spring中间件逻辑分析(怎么把Mapper接口注册到Spring中)

    1.      文档介绍 1.1.      为什么要写这个文档 接触Spring和MyBatis也挺久的了,但是一直还停留在使用的层面上,导致很多时候光知道怎么用,而不知道其具体原理,这样就很难做一 ...

随机推荐

  1. n98-magerun2.phar

    installl: 1,cd /usr/local/bin && curl -O https://files.magerun.net/n98-magerun2.phar 2,chmod ...

  2. 【nowcoder-2017校招真题】保留最大的数

    牛客在线编程-保留最大的数 题目描述 给定一个十进制的正整数number,选择从里面去掉一部分数字,希望保留下来的数字组成的正整数最大. 输入描述: 输入为两行内容,第一行是正整数number,1 ≤ ...

  3. emwin 之 LISTWVIEW 控件禁止列滑动

    @2019-02-25 [小记] hHeader = LISTVIEW_GetHeader(hListView); WM_DisableWindow(hHeader);

  4. 牛客网 223C 区区区间间间(单调栈)

    题目链接:区区区间间间 题意:给出长度为n的数字序列ai,定义区间(l,r)的价值为, 请你计算出. 题解:单调栈求ai左边和右边第一个比它小的位置,需要减去ai的个数为$(R_i-i+1)*(i-L ...

  5. [BJOI2019] 光线

    看起来很麻烦,做起来并不难的题 以下设:$a_i=\frac{a_i}{100},b_i=\frac{b_i}{100}$ 显然,如果$b_i=0$的话,直接求$\Pi a_i$就是答案. 解决反射问 ...

  6. 如何将JPG格式的图片转换成PNG格式

    study from : https://jingyan.baidu.com/article/6079ad0e63a4fc28ff86db37.html

  7. Tensorflow基本语法

    一.tf.Variables() import tensorflow as tf Weights = tf.Variable(tf.random_uniform([1], -1.0, 1.0)) se ...

  8. Hbase CMS GC 调优。

    export HBASE_OPTS="-XX:+UseConcMarkSweepGC" export HBASE_LOG_DIR=/app/hbase/logexport HBAS ...

  9. LFYZ-OJ ID: 1009 阶乘和

    思路 循环n次,每次计算i的阶乘i!,并加入sum中. n的范围从1~100,这里一定要使用高精度运算,涉及到"高精度乘低精度","高精度加高精度". 避免每次 ...

  10. JAVA发红包案例

    模拟拼手气红包* 对于指定总金额以及红包个数,可以生成不同金额的红包,*,每个红包金额随机生成. * 分析这个题目:* 1.首先需要一个分发红包的方法.输入的参数是 总金额 以及 红包个数.* 按照这 ...