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

参考: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. 忘掉Ghost!利用Win10自带功能,玩转系统备份&恢复 -- 关于系统恢复的深度思考

    上一篇文章讲了,系统可以正常启动,如何从D盘恢复系统到C盘的情况. 如果系统不能启动,要怎么去恢复系统,恢复后会是什么结果? 先说明系统结构: 系统版本:Windows 10 (1709) 硬盘1(5 ...

  2. redis简单命令总结

    1.连接到redis服务器:redis-cli -h 127.0.0.1 -p 6379 -a 密码 select index 切换 redis 数据库 flushdb 删除当前数据库所有的 key ...

  3. 分布式监控系统开发【day38】:报警自动升级代码解析及测试(八)

    一.报警自动升级代码解析 发送邮件代码 def action_email(self,action_obj,action_operation_obj,host_id,trigger_data): ''' ...

  4. 金融量化分析【day110】:Pandas的Series对象

    一.pandas简介安装 pandas是一个强大的python数据分析的工具包 pandsa是基于NumPy构建的 1.pandas的主要功能 1.具备对其功能的数据结构DataFrame.Serie ...

  5. 《Java》第四周学习总结

    20175301 李锦然 一:本周学习内容 1:学习第五章视频 2:做实验 第五章主要讲的是子类与父类的关系,子类的继承与多态,final类super类等内容 仓库地址https://gitee.co ...

  6. [物理学与PDEs]第2章习题11 Lagrange 形式的一维理想流体力学方程组在强间断线上的间断连接条件

    对由第 10 题给出的 Lagrange 形式的一维理想流体力学方程组, 给出解在强间断线上应满足的间断连接条件 (假设体积力 $F\equiv 0$). 解答: $$\beex \bea \sez{ ...

  7. luogu 4042 有后效性的dp

    存在有后效性的dp,但转移方程 f[i] = min( f[i], s[i] + sigma f[j] ( j 是后效点) ) 每次建当前点和 转移点的边 e1, 某点和其会影响的点 e2 spfa ...

  8. PHP中ajax返回数据类型为JSON数据的处理

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. APPLE-SA-2019-3-25-1 iOS 12.2

    APPLE-SA-2019-3-25-1 iOS 12.2 iOS 12.2 is now available and addresses the following: CFStringAvailab ...

  10. idea+maven+ssm搭建boot_crm项目遇到的问题

    使用idea+maven+ssm搭建一个boot_crm项目,遇到的问题如下: 1.环境搭建好了,相关配置文件都配置好了,也部署到了tomcat,但是无法启动首页. 通过百度,google找到了,原因 ...