springCloud微服务系列——链路跟踪第五篇——mybatis链路跟踪器

目录

 

一、简介

二、思路

interceptor的创建源码分析

spring上下文之外获得bean

三、示例代码


一、简介

             这篇文章总结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;
	}

}

https://github.com/wulinfeng2/luminary-component 

猜你喜欢

转载自blog.csdn.net/guduyishuai/article/details/81381445