目录
一、简介
这篇文章总结mybatis链路跟踪器的实现
二、思路
拦截的话用mybatis自带的interceptor就可以了,这里有一点需要注意。mybatis的interceptor是没办法注入到spring中的。
interceptor的创建源码分析
mybatis的interceptor是通过反射构建出来的,是在启动的时候通过XMLConfigBuilder类解析ml文件,然后根据类名调用classLoader加载进来,再通过反射实例化的。因此不可能作为bean让spring管理。
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}
spring上下文之外获得bean
由于interceptor无法注入,那么我们想要使用spring管理的bean或者配置信息怎么办,我们可以通过写一个方法类,该类注册成spring的bean,然后再将需要的bean或属性注入到它的静态成员变量中。
举个例子
public class ProfileContext {
public static String profile;
public void setProfile(String profile) {
ProfileContext.profile = profile;
}
}
@Configuration
public class TrackerAutoConfiguration {
@Value("${spring.profiles.active:default}")
private String profile;
@Bean
public ProfileContext profileContext() throws IOException {
ProfileContext profileHelper = new ProfileContext();
profileHelper.setProfile(profile);
return profileHelper;
}
}
三、示例代码
@Slf4j
@Intercepts({
@Signature(type = Executor.class, args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}, method = "query"),
@Signature(type = Executor.class, args = {MappedStatement.class, Object.class}, method = "update")
})
public class MybatisTracker extends GenericTracker implements Interceptor {
private static String MAPPER_SEPARATOR = "Dao.";
private static String JDBC_PREFIX = "jdbc:";
public MybatisTracker() {
super();
}
/**
* <p>Title: </p>
* <p>Description: </p>
* @param traceClient
*/
public MybatisTracker(TraceClient traceClient) {
super(traceClient);
}
/* (non-Javadoc)
* <p>Title: intercept</p>
* <p>Description: </p>
* @param arg0
* @return
* @throws Throwable
* @see org.apache.ibatis.plugin.Interceptor#intercept(org.apache.ibatis.plugin.Invocation)
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
log.info("mybatis tracker");
TraceHolder traceHolder = new TraceHolder();
Object result = null;
try {
Gson gson = new Gson();
if(traceClient == null)
traceClient = getTraceClient();
String sqlId = "";
Object parameter = null;
MappedStatement mappedStatement = null;
BoundSql boundSql = null;
Configuration configuration = null;
String jdbcUrl = "";
Object[] args = invocation.getArgs();
for(Object arg : args) {
if(arg != null) {
if(arg instanceof MappedStatement) {
mappedStatement = (MappedStatement) arg;
sqlId = mappedStatement.getId();
}
else if(!(arg instanceof RowBounds) && !(arg instanceof ResultHandler)) {
parameter = arg;
}
}
}
if(mappedStatement !=null && parameter != null) {
boundSql = mappedStatement.getBoundSql(parameter);
configuration = mappedStatement.getConfiguration();
}
String methodName = sqlId.substring(sqlId.indexOf(MAPPER_SEPARATOR)+MAPPER_SEPARATOR.length());
String serviceName = sqlId.substring(0, sqlId.lastIndexOf("."));
String requestParam = boundSql.getSql();
if(parameter != null) {
requestParam = requestParam + "|" + gson.toJson(parameter);
}
traceHolder.setProfile(getProfile());
traceHolder.setRpcType(RpcTypeEnum.DB.name());
traceHolder.setServiceCategory("mybatis");
traceHolder.setServiceName(serviceName);
traceHolder.setMethodName(methodName);
traceHolder.setRequestParam(requestParam);
preHandle(traceHolder);
result = invocation.proceed();
if(configuration != null) {
DataSource dataSource = configuration.getEnvironment().getDataSource();
if(dataSource instanceof DruidDataSource) {
jdbcUrl = ((DruidDataSource) dataSource).getUrl();
}
}
String serviceHost = jdbcUrl.substring(jdbcUrl.indexOf(JDBC_PREFIX)+JDBC_PREFIX.length(), jdbcUrl.indexOf("?"));
traceHolder.getEntity().setServiceHost(serviceHost);
traceHolder.getEntity().setResponseInfo(result.toString());
postHandle(traceHolder);
} catch(Exception e) {
log.error(e.getMessage(), e);
exceptionHandle(traceHolder, e);
}
return result;
}
/* (non-Javadoc)
* <p>Title: plugin</p>
* <p>Description: </p>
* @param arg0
* @return
* @see org.apache.ibatis.plugin.Interceptor#plugin(java.lang.Object)
*/
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
/* (non-Javadoc)
* <p>Title: setProperties</p>
* <p>Description: </p>
* @param arg0
* @see org.apache.ibatis.plugin.Interceptor#setProperties(java.util.Properties)
*/
@Override
public void setProperties(Properties properties) {
}
public String getProfile() {
log.warn("默认实现方法");
return null;
}
public TraceClient getTraceClient() {
log.warn("默认实现方法");
return null;
}
}