Springboot 整合 大众点评cat
这里用apache-tomcat-8.5.65-windows-x64 发布cat
1 下载cat的war包,这里下载的是cat-home-3.0.0.war 改名为cat.war
并放在 tomcat的webapp目录下,启动tomcat这时候会解压缩war,
第一步的目的就是为了解压war,在D盘下生成目录 D:\data\appdatas\cat
2在 D:\data\appdatas\cat下添加这3个xml文件
client.xml内容如下:
<?xml version="1.0" encoding="utf-8"?>
<config mode="client" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd">
<servers>
<server ip="172.16.9.114" port="2280" http-port="8080" />
</servers>
</config>
datasources.xml内容如下:
<?xml version="1.0" encoding="utf-8"?>
<data-sources>
<data-source id="cat">
<maximum-pool-size>3</maximum-pool-size>
<connection-timeout>1s</connection-timeout>
<idle-timeout>10m</idle-timeout>
<statement-cache-size>1000</statement-cache-size>
<properties>
<driver>com.mysql.jdbc.Driver</driver>
<url><![CDATA[jdbc:mysql://172.16.6.56:3306/cat]]></url> <!-- 请替换为真实数据库URL及Port -->
<user>root</user>
<password>123456</password>
<connectionProperties><![CDATA[useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&socketTimeout=120000]]></connectionProperties>
</properties>
</data-source>
</data-sources>
server.xml内容如下:
<?xml version="1.0" encoding="utf-8"?>
<!-- Configuration for development environment-->
<config local-mode="false" hdfs-machine="false" job-machine="true" alert-machine="true">
<storage local-base-dir="D:/data/appdatas/cat/bucket/" max-hdfs-storage-time="15" local-report-storage-time="7" local-logivew-storage-time="7">
</storage>
<console default-domain="Cat" show-cat-domain="true">
<!--将172.16.90.114修改为部署CAT的内网IP,请不要写127.0.0.1和外网IP -->
<remote-servers>172.16.9.114:8080</remote-servers>
</console>
</config>
Ps:172.16.90.114是本机ip 不能写成127.0.0.1
3 启动tomcat输入Url: http://172.16.9.114:8080/cat/r 用户名密码都是admin
4 修改配置 config下的ip改为本机ip
5看到服务端正常,说明成功了
6 在项目中添加依赖 没有这个jar包的可以自己用源代码打包 也可以在这个仓库上下载
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-client</artifactId>
<version>3.0.0</version>
</dependency>
<repository>
<id>unidal.nexus</id>
<url>http://unidal.org/nexus/content/repositories/releases/</url>
</repository>
添加aop类
package com.study.web.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.dianping.cat.Cat;
@Component
@Aspect
@Order(2)
public class CatMetricAop {
private static final Logger LOGGER = LoggerFactory.getLogger(CatMetricAop.class);
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) " +
"||@annotation(org.springframework.web.bind.annotation.PostMapping)" +
"||@annotation(org.springframework.web.bind.annotation.GetMapping)")
public void controllerAspect() {
}
@Around("controllerAspect()")
public Object around(ProceedingJoinPoint joinPoint) {
Object value = null;
try {
String method = joinPoint.getSignature().getName();
Cat.logMetricForCount(method);
value = joinPoint.proceed();
} catch (Throwable throwable) {
// Cat.logEvent("URL.Throwable", throwable.toString());
LOGGER.error("CatMetricAop异常", throwable);
}
return value;
}
}
package com.study.web.aop;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.mybatis.spring.transaction.SpringManagedTransaction;
import org.springframework.util.ReflectionUtils;
import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
/**
* 对MyBatis进行拦截,添加Cat监控
* @author Steven
*/
@Intercepts({
@Signature(method = "query", type = Executor.class, args = {
MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class}),
@Signature(method = "update", type = Executor.class, args = {MappedStatement.class, Object.class})
})
public class CatMybatisPlugin implements Interceptor {
private static Log logger = LogFactory.getLog(CatMybatisPlugin.class);
//缓存,提高性能
private static final Map<String, String> sqlURLCache = new ConcurrentHashMap<String, String>(256);
private static final String EMPTY_CONNECTION = "jdbc:mysql://unknown:3306/%s?useUnicode=true";
private Executor target;
// druid 数据源的类名称
private static final String DruidDataSourceClassName = "com.alibaba.druid.pool.DruidDataSource";
// dbcp 数据源的类名称
private static final String DBCPBasicDataSourceClassName = "org.apache.commons.dbcp.BasicDataSource";
// dbcp2 数据源的类名称
private static final String DBCP2BasicDataSourceClassName = "org.apache.commons.dbcp2.BasicDataSource";
// c3p0 数据源的类名称
private static final String C3P0ComboPooledDataSourceClassName = "com.mchange.v2.c3p0.ComboPooledDataSource";
// HikariCP 数据源的类名称
private static final String HikariCPDataSourceClassName = "com.zaxxer.hikari.HikariDataSource";
// BoneCP 数据源的类名称
private static final String BoneCPDataSourceClassName = "com.jolbox.bonecp.BoneCPDataSource";
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
//得到类名,方法
String[] strArr = mappedStatement.getId().split("\\.");
String methodName = strArr[strArr.length - 2] + "." + strArr[strArr.length - 1];
Transaction t = Cat.newTransaction("SQL", methodName);
//得到sql语句
Object parameter = null;
if (invocation.getArgs().length > 1) {
parameter = invocation.getArgs()[1];
}
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
Configuration configuration = mappedStatement.getConfiguration();
String sql = showSql(configuration, boundSql);
//获取SQL类型
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
Cat.logEvent("SQL.Method", sqlCommandType.name().toLowerCase(), Message.SUCCESS, sql);
String s = this.getSQLDatabase();
Cat.logEvent("SQL.Database", s);
Object returnObj = null;
try {
returnObj = invocation.proceed();
t.setStatus(Transaction.SUCCESS);
} catch (Exception e) {
Cat.logError(e);
} finally {
t.complete();
}
return returnObj;
}
private DataSource getDataSource() {
org.apache.ibatis.transaction.Transaction transaction = this.target.getTransaction();
if (transaction == null) {
logger.error(String.format("Could not find transaction on target [%s]", this.target));
return null;
}
if (transaction instanceof SpringManagedTransaction) {
String fieldName = "dataSource";
Field field = ReflectionUtils.findField(transaction.getClass(), fieldName, DataSource.class);
if (field == null) {
logger.error(String.format("Could not find field [%s] of type [%s] on target [%s]",
fieldName, DataSource.class, this.target));
return null;
}
ReflectionUtils.makeAccessible(field);
DataSource dataSource = (DataSource) ReflectionUtils.getField(field, transaction);
return dataSource;
}
logger.error(String.format("---the transaction is not SpringManagedTransaction:%s", transaction.getClass().toString()));
return null;
}
/**
* 重写 getSqlURL 方法
*
* @author fanlychie (https://github.com/fanlychie)
*/
private String getSqlURL() {
// 客户端使用的数据源
DataSource dataSource = this.getDataSource();
if (dataSource != null) {
// 处理常见的数据源
switch (dataSource.getClass().getName()) {
// druid
case DruidDataSourceClassName:
return getDataSourceSqlURL(dataSource, DruidDataSourceClassName, "getUrl");
// dbcp
case DBCPBasicDataSourceClassName:
return getDataSourceSqlURL(dataSource, DBCPBasicDataSourceClassName, "getUrl");
// dbcp2
case DBCP2BasicDataSourceClassName:
return getDataSourceSqlURL(dataSource, DBCP2BasicDataSourceClassName, "getUrl");
// c3p0
case C3P0ComboPooledDataSourceClassName:
return getDataSourceSqlURL(dataSource, C3P0ComboPooledDataSourceClassName, "getJdbcUrl");
// HikariCP
case HikariCPDataSourceClassName:
return getDataSourceSqlURL(dataSource, HikariCPDataSourceClassName, "getJdbcUrl");
// BoneCP
case BoneCPDataSourceClassName:
return getDataSourceSqlURL(dataSource, BoneCPDataSourceClassName, "getJdbcUrl");
}
}
return null;
}
/**
* 获取数据源的SQL地址
*
* @param dataSource 数据源
* @param runtimeDataSourceClassName 运行时真实的数据源的类名称
* @param sqlURLMethodName 获取SQL地址的方法名称
*
* @author fanlychie (https://github.com/fanlychie)
*/
private String getDataSourceSqlURL(DataSource dataSource, String runtimeDataSourceClassName, String sqlURLMethodName) {
Class<?> dataSourceClass = null;
try {
dataSourceClass = Class.forName(runtimeDataSourceClassName);
} catch (ClassNotFoundException e) {}
Method sqlURLMethod = ReflectionUtils.findMethod(dataSourceClass, sqlURLMethodName);
return (String) ReflectionUtils.invokeMethod(sqlURLMethod, dataSource);
}
private String getSQLDatabase() {
// String dbName = RouteDataSourceContext.getRouteKey();
String dbName = null; //根据设置的多数据源修改此处,获取dbname
if (dbName == null) {
dbName = "DEFAULT";
}
String url = CatMybatisPlugin.sqlURLCache.get(dbName);
if (url != null) {
return url;
}
url = this.getSqlURL();//目前监控只支持mysql ,其余数据库需要各自修改监控服务端
if (url == null) {
url = String.format(EMPTY_CONNECTION, dbName);
}
CatMybatisPlugin.sqlURLCache.put(dbName, url);
return url;
}
/**
* 解析sql语句
*
* @param configuration
* @param boundSql
* @return
*/
public String showSql(Configuration configuration, BoundSql boundSql) {
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (parameterMappings.size() > 0 && parameterObject != null) {
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(parameterObject)));
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
Object obj = metaObject.getValue(propertyName);
sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
Object obj = boundSql.getAdditionalParameter(propertyName);
sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));
}
}
}
}
return sql;
}
/**
* 参数解析
*
* @param obj
* @return
*/
private String getParameterValue(Object obj) {
String value = null;
if (obj instanceof String) {
value = "'" + obj.toString() + "'";
} else if (obj instanceof Date) {
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
value = "'" + formatter.format(new Date()) + "'";
} else {
if (obj != null) {
value = obj.toString();
} else {
value = "";
}
}
return value;
}
@Override
public Object plugin(Object target) {
if (target instanceof Executor) {
this.target = (Executor) target;
return Plugin.wrap(target, this);
}
return target;
}
@Override
public void setProperties(Properties properties) {
}
}
package com.study.web.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.dianping.cat.servlet.CatFilter;
@Configuration
public class CatFilterConfigure {
@Bean
public FilterRegistrationBean catFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
CatFilter filter = new CatFilter();
registration.setFilter(filter);
registration.addUrlPatterns("/*");
registration.setName("cat-filter");
registration.setOrder(1);
return registration;
}
}
package com.study.web.config;
import javax.sql.DataSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import com.study.web.aop.CatMybatisPlugin;
import com.zaxxer.hikari.HikariDataSource;
@Configuration
public class MybatisConfig implements EnvironmentAware {
private Environment environment;
@Bean
public HikariDataSource getDateSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(environment.getProperty("spring.datasource.url"));
dataSource.setUsername(environment.getProperty("spring.datasource.username"));
dataSource.setPassword(environment.getProperty("spring.datasource.password"));
// dataSource.setDriverClassName(environment.getProperty("spring.datasource.driverClassName"));
return dataSource;
}
@Bean
public SqlSessionFactory getSqlSession(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
CatMybatisPlugin catMybatisPlugin = new CatMybatisPlugin();
factoryBean.setPlugins(new Interceptor[] {
catMybatisPlugin
});
Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml");
factoryBean.setMapperLocations(resources);
SqlSessionFactory sessionFactory = factoryBean.getObject();
return sessionFactory;
}
@Bean
public MapperScannerConfigurer getMapperScannerConfigurer(SqlSessionFactory sqlSessionFactory) {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.study.mapper");
configurer.setSqlSessionFactory(sqlSessionFactory);
return configurer;
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
//
// @Bean
// @Override
// public PlatformTransactionManager annotationDrivenTransactionManager() {
// return new DataSourceTransactionManager(dataSource);
// }
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
这样基本就可以了 这个mybatise拦截器 还有一种简单的写法:代码在这一篇文章中https://www.toutiao.com/i6951332715186766368/
本文暂时没有评论,来添加一个吧(●'◡'●)