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

参考: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. Educational Codeforces Round 60 (Rated for Div. 2)

    A. Best Subsegment 题意 找 连续区间的平均值  满足最大情况下的最长长度 思路:就是看有几个连续的最大值 #include<bits/stdc++.h> using n ...

  2. Django+Vue打造购物网站(四)

    首页商品类别数据显示 商品分类接口 大概需要两个,一个显示三个类别 一个显示类别及类别下的全部商品 现在开始写商品的接口 首先编写三个分类的serializer class CategorySeria ...

  3. Scrapy 框架 中间件,信号,定制命令

    中间件 下载器中间件 写中间件 from scrapy.http import HtmlResponse from scrapy.http import Request class Md1(objec ...

  4. Java斗地主案例、异常和自定义异常整理

    模拟斗地主洗牌发牌 1.1 案例介绍 按照斗地主的规则,完成洗牌发牌的动作. 具体规则: 1. 组装54张扑克牌 2. 将54张牌顺序打乱 3. 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张 ...

  5. NLTK基础

    Python上著名的⾃然语⾔处理库 ⾃带语料库,词性分类库 ⾃带分类,分词,等等功能 强⼤的社区⽀持 还有N多的简单版wrapper 安装语料库 # 方式一 import nltk nltk.down ...

  6. 【VS】VS2013 未找到与约束contractname 匹配的导出

    #事故现场 今天win10更新后,打开vs2013新建项目报错: #解决方案: 1.控制面板->程序->程序和功能,找到 Entity Framework Tools for Visual ...

  7. 针对主机CPU idle性能情况需求脚本编写

    [环境介绍] 系统环境:Linux + osw + python 2.7.10 [背景描述] 需求:当系统服务器出现性能告警的时候,需要定位具体的时间点来进行有针对性的去查询产生的问题.OSW提供了很 ...

  8. keras的网络结构与网络配置

    摘自: https://www.cnblogs.com/Anita9002/p/8136357.html Keras的网络配置

  9. HttpUtility.UrlEncode编码重写

    1. 某些系统方法,例如.NET系统方法HttpUtility.UrlEncode会将‘=’编码成‘%3d’,而不是%3D,导致加密签名通不过验证,请开发者注意检查. 2.Java 1.3和早期版本中 ...

  10. 【easy】404. Sum of Left Leaves

    求所有左节点的和. /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; ...