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也挺久的了,但是一直还停留在使用的层面上,导致很多时候光知道怎么用,而不知道其具体原理,这样就很难做一 ...
随机推荐
- Java使用J4L识别验证码
1.首先要下载j4l的相应文件和jar 下载地址:http://www.java4less.com/ocrtools/ocrtools.php?info=download 2.下载完成之后解压,文件目 ...
- 【XSY3154】入门多项式 高斯消元
题目大意 给你一个 \(n\times n\)的矩阵 \(A\),求次数最小且最高次项为 \(1\) 的多项式 \(F(x)\),满足 \(F(A)=0\). 所有操作都对 \(p\) 取模. \(n ...
- MT【321】分类线性规划
若二次函数$f(x)=ax^2+bx+c(a,b,c>0)$有零点,则$\min\{\dfrac{b+c}{a},\dfrac{c+a}{b},\dfrac{a+b}{c}\}$ 的最大值为__ ...
- 并发容器学习—ConcurrentSkipListMap与ConcurrentSkipListSet 原
一.ConcurrentSkipListMap并发容器 1.ConcurrentSkipListMap的底层数据结构 要学习ConcurrentSkipListMap,首先要知道什么是跳表或跳 ...
- tcpdump在linux上的常见用法
https://www.cnblogs.com/ggjucheng/archive/2012/01/14/2322659.html tcpdump -i [interface] -w cap.cap ...
- mongodb中比较级查询条件:($lt $lte $gt $gte)(大于、小于)、查找条件
查询表中学生年级大于20,如下: db.getCollection('student').find({'age':{'$gt':'20'}}) $lt < (less than ) ...
- 降维【PCA & SVD】
PCA(principle component analysis)主成分分析 理论依据 最大方差理论 最小平方误差理论 一.最大方差理论(白面机器学习) 对一个矩阵进行降维,我们希望降维之后的每一维数 ...
- Gaussian Process for Regression
python风控评分卡建模和风控常识(博客主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005214003&am ...
- 金融量化分析【day110】:金融基础知识
一.股票 股票: 股票是股份公司发给出资人的一种凭证,股票的持有者就是股份公司的股东. 股票的面值与市值 面值表示票面金额 市值表示市场价值 上市/IPO: 企业通过证券交易所公开向社会增发股票以募集 ...
- React 记录(7)
React文档:https://www.reactjscn.com/docs/handling-events.html 慢慢学习:对照教程文档,逐句猜解,截图 React官网:https://reac ...