aop切入mapper接口
***************************************分割线******************************************************
参考: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);
所以重新包装一下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接口的更多相关文章
- 由一个RABBITMQ监听器死循环引出的SPRING中BEAN和MAPPER接口的注入问题
1 @Slf4j 2 @RestController 3 @Component 4 public class VouchersReceiverController implements Message ...
- Spring AOP在函数接口调用性能分析及其日志处理方面的应用
面向切面编程可以实现在不修改原来代码的情况下,增加我们所需的业务处理逻辑,比如:添加日志.本文AOP实例是基于Aspect Around注解实现的,我们需要在调用API函数的时候,统计函数调用的具体信 ...
- Mybatis的mapper接口接受的参数类型
最近项目用到了Mybatis,学一下记下来. Mybatis的Mapper文件中的select.insert.update.delete元素中有一个parameterType属性,用于对应的mappe ...
- MyBatis Mapper 接口如何通过JDK动态代理来包装SqlSession 源码分析
我们以往使用ibatis或者mybatis 都是以这种方式调用XML当中定义的CRUD标签来执行SQL 比如这样 <?xml version="1.0" encoding=& ...
- mybatis的基本配置:实体类、配置文件、映射文件、工具类 、mapper接口
搭建项目 一:lib(关于框架的jar包和数据库驱动的jar包) 1,第一步:先把mybatis的核心类库放进lib里
- Mybatis源码解析-MapperRegistry注册mapper接口
知识储备 SqlsessionFactory-mybatis持久层操作数据的根本,具体的解析是通过SqlSessionFactoryBean生成的,具体的形成可见>>>Spring ...
- mybatis 详解(六)------通过mapper接口加载映射文件
通过 mapper 接口加载映射文件,这对于后面 ssm三大框架 的整合是非常重要的.那么什么是通过 mapper 接口加载映射文件呢? 我们首先看以前的做法,在全局配置文件 mybatis-conf ...
- Mybatis中是否需要依赖配置文件的名称要和mapper接口的名称一致 params错误
一:当核心配置文件mapper标签下以resource形式指向依赖配置文件时,不需要 这样就可以加载到其相应的依赖配置文件通过namespace找到其相应的方法 二:如果mapper标签下以packa ...
- MyBatis-Spring中间件逻辑分析(怎么把Mapper接口注册到Spring中)
1. 文档介绍 1.1. 为什么要写这个文档 接触Spring和MyBatis也挺久的了,但是一直还停留在使用的层面上,导致很多时候光知道怎么用,而不知道其具体原理,这样就很难做一 ...
随机推荐
- Educational Codeforces Round 60 (Rated for Div. 2)
A. Best Subsegment 题意 找 连续区间的平均值 满足最大情况下的最长长度 思路:就是看有几个连续的最大值 #include<bits/stdc++.h> using n ...
- Django+Vue打造购物网站(四)
首页商品类别数据显示 商品分类接口 大概需要两个,一个显示三个类别 一个显示类别及类别下的全部商品 现在开始写商品的接口 首先编写三个分类的serializer class CategorySeria ...
- Scrapy 框架 中间件,信号,定制命令
中间件 下载器中间件 写中间件 from scrapy.http import HtmlResponse from scrapy.http import Request class Md1(objec ...
- Java斗地主案例、异常和自定义异常整理
模拟斗地主洗牌发牌 1.1 案例介绍 按照斗地主的规则,完成洗牌发牌的动作. 具体规则: 1. 组装54张扑克牌 2. 将54张牌顺序打乱 3. 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张 ...
- NLTK基础
Python上著名的⾃然语⾔处理库 ⾃带语料库,词性分类库 ⾃带分类,分词,等等功能 强⼤的社区⽀持 还有N多的简单版wrapper 安装语料库 # 方式一 import nltk nltk.down ...
- 【VS】VS2013 未找到与约束contractname 匹配的导出
#事故现场 今天win10更新后,打开vs2013新建项目报错: #解决方案: 1.控制面板->程序->程序和功能,找到 Entity Framework Tools for Visual ...
- 针对主机CPU idle性能情况需求脚本编写
[环境介绍] 系统环境:Linux + osw + python 2.7.10 [背景描述] 需求:当系统服务器出现性能告警的时候,需要定位具体的时间点来进行有针对性的去查询产生的问题.OSW提供了很 ...
- keras的网络结构与网络配置
摘自: https://www.cnblogs.com/Anita9002/p/8136357.html Keras的网络配置
- HttpUtility.UrlEncode编码重写
1. 某些系统方法,例如.NET系统方法HttpUtility.UrlEncode会将‘=’编码成‘%3d’,而不是%3D,导致加密签名通不过验证,请开发者注意检查. 2.Java 1.3和早期版本中 ...
- 【easy】404. Sum of Left Leaves
求所有左节点的和. /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; ...