TDDL与Spring Boot集成Version报错——跟踪与解决
先说背景:公司采用diamond+tddl,这套技术来做web管理。本人处于好奇率先体验了下spring-boot,于是就有了spring-boot+tddl的组合。但是jar包上线后,屡屡发现一条error日志不痛不痒的出现在日志文件中,处于程序员的本能,怎么能允许error日志出现在我的系统中呢!
于是,展开了一段tddl与spring-boot的爱恨之旅...
挣扎期
首先看错误提示:
2017-09-27 11:15:58,428 [main] ERROR com.taobao.tddl.common.utils.version.Version:74 - [TDDL] check guava version is recommend <= 15.0(the minimum version), please upgrade guava jar version, tddl version: recommend
java.lang.IllegalStateException: check guava version is recommend <= 15.0(the minimum version), please upgrade guava jar version
at com.taobao.tddl.common.utils.version.Version.validVersion(Version.java:122)
at com.taobao.tddl.common.utils.version.Version.<clinit>(Version.java:36)
at com.taobao.tddl.monitor.logger.LoggerInit.initTddlLog(LoggerInit.java:42)
at com.taobao.tddl.monitor.logger.LoggerInit.<clinit>(LoggerInit.java:32)
at com.taobao.tddl.group.jdbc.TGroupDataSource.doInit(TGroupDataSource.java:117)
at com.taobao.tddl.common.model.lifecycle.AbstractLifecycle.init(AbstractLifecycle.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
太明显了!jar包版本不对嘛!——so easy!
于是取mvn里面,调查版本,发现没啥问题呀!guava(21.0);druid(1.1.2)。尝试了maven的diagram图和mvn dependency:tree
,各种分析都没啥问题!
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.2</version>
</dependency>
于是,我迷茫了!!!!!!!
突破期
作为一个合格的程序员,不放弃,不抛弃是我们的原则!我想起来实习的时候,公司一位技术大牛教过我,怎么在不下载完整源码的情况下,直接调试第三方jar。
首先需要一点背景知识,就是java的类加载机制!
类加载
最基本的知识就是类加载的模型和父类委托机制:
Bootstrap ClassLoader:加载JAVA_HOME\lib下的jar
|
Extension ClassLoader:加载JAVA_HOME\ext\lib下的jar
|
Application ClassLoader:加载用户路径上指定的类
父类委托机制,其实就是每次加载的时候,会优先把加载的任务交给上一层,上一层再交给上一层。如果上一层找到,就使用这个jar;如果找不到再由下一层寻找。也就是说,如果同样的两个jar,放在JAVA_HOME\lib里面的会优先使用。
有些人可能会有疑问,这根本地调试有什么关系?别着急,在开发环境或者应用部署环境中,应用类的加载也是有一定的顺序的。比如会先读取classes下面的文件,找不到的话,在读取lib中的文件。
了解这个classes和lib的优先级,就足够我们调试用了!
spring-boot jar目录结构
另外一个背景知识,就是需要了解spring-boot jar的目录结构。
这样我们编译出的class会进入到classes目录下,而其他的第三方的jar会进入lib目录。
开始源码跟踪
根据error日志的跟踪,可以发现最终出错的位置是在Version的validVersion方法。所以我们直接看一下源码,并且根据源码直接拷贝出来放入我们自己的工程:
public final class Version {
...
// 这里是检查常用jar包版本的地方,可以看到tddl强烈要求druid、daimond、guava的版本
static {
...
// 检查下经常性冲突的两个包
Version.checkDuplicate("com/alibaba/druid/pool/DruidDataSource.class", false);
validVersion("druid", "com/alibaba/druid/pool/DruidDataSource.class", "1.0.6");
Version.checkDuplicate("com/taobao/diamond/client/Diamond.class", false);
validVersion("diamond", "com/taobao/diamond/client/Diamond.class", "3.6.8");
Version.checkDuplicate("com/google/common/collect/MapMaker.class", false);
validVersion("guava", "com/google/common/collect/MapMaker.class", "15.0");
}
// 这里是检查版本的地方
public static boolean validVersion(String name, String path, String minVersion) {
try {
if (minVersion == null) {
return true;
}
Long minv = convertVersion(minVersion);
Enumeration<URL> urls = Version.class.getClassLoader().getResources(path);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if (url != null) {
String file = url.getFile();
if (file != null && file.length() > 0) {
// 主要的点是这里!根据file的名字获取版本
String version = getVerionByPath(file);
// 为了方便运行期调试,直接输出关键的信息 System.out.println("------------------------------------");
System.out.println("完整的路径为:"+file);
System.out.println("检测到version为:"+version);
System.out.println("------------------------------------");
if (checkVersionNecessary(version)) {
Long ver = convertVersion(version);
if (ver < minv) {
throw new IllegalStateException("check " + name + " version is " + version + " <= "
+ minVersion + "(the minimum version), please upgrade "
+ name + " jar version");
}
}
}
}
}
} catch (Throwable e) { // 防御性容错
logger.error(e.getMessage(), e);
}
return true;
}
}
目录结构如下:
运行后就发现,得到下面的输出:
------------------------------------
完整的路径为:file:/Users/xingoo/IdeaProjects/test-recommend/target/recommend.jar!/BOOT-INF/lib/guava-20.0.jar!/com/google/common/collect/MapMaker.class
检测到version为:recommend
------------------------------------
呵呵哒!原来error日志已经提示了版本为recommend,如果有经验的话,应该直接就能发现版本是错的。不过对于新手来说,真是看不出来啊。
那么接下来就可以分析一下为什么版本会出错了!
talk is cheap, show me your code!
public static String getVerionByPath(String file) {
if (file != null && file.length() > 0 && StringUtils.contains(file, ".jar")) {
int index = StringUtils.indexOf(file, ".jar");
file = file.substring(0, index);
int i = file.lastIndexOf('/');
if (i >= 0) {
file = file.substring(i + 1);
}
i = file.indexOf("-");
if (i >= 0) {
file = file.substring(i + 1);
}
while (file.length() > 0 && !Character.isDigit(file.charAt(0))) {
i = file.indexOf("-");
if (i >= 0) {
file = file.substring(i + 1);
} else {
break;
}
}
return file;
} else {
return null;
}
}
这里用的StringUtils.indexOf
获得第一个jar前面的部分,由于我的spring-boot打出来的jar包,是嵌套jar的。所以获取第一个就出错了!
修改方法, 把indexOf替换成lastIndexOf就行了:
...
int index = StringUtils.lastIndexOf(file, ".jar");
...
最终解决办法
想要一条error日志也没有,可以参考下面的方法:
- 把下面的代码考入工程,记住不要修改包名,直接放在com.tddl.common.utils.version下!
- 并且关闭tddl的各种版本检查,
不过因为两个error报错,就把整个tddl的版本检测给摘掉好像太暴力。所以最好还是等官网来修复吧!:
public final class Version {
private static final Logger logger = LoggerFactory.getLogger(Version.class);
private static final Package myPackage = VersionAnnotation.class.getPackage();
private static final VersionAnnotation va = myPackage.getAnnotation(VersionAnnotation.class);
private static final String VERSION = getVersion(Version.class, "5.1.7");
static {
// 检查是否存在重复的jar包
// Version为tddl5.x之后的版本检测类
// 如果Version检测没有发现重复,再和tddl3.x系列进行检查,ThreadLocalMap兼容了tddl3.x的类路径
// if (!Version.checkDuplicate(Version.class)) {
// Version.checkDuplicate(ThreadLocalMap.class);
// }
// 检查下经常性冲突的两个包
// Version.checkDuplicate("com/alibaba/druid/pool/DruidDataSource.class", false);
// validVersion("druid", "com/alibaba/druid/pool/DruidDataSource.class", "1.0.6");
// Version.checkDuplicate("com/taobao/diamond/client/Diamond.class", false);
// validVersion("diamond", "com/taobao/diamond/client/Diamond.class", "3.6.8");
// Version.checkDuplicate("com/google/common/collect/MapMaker.class", false);
// validVersion("guava", "com/google/common/collect/MapMaker.class", "15.0");
}
private Version() {
}
...
}
TDDL与Spring Boot集成Version报错——跟踪与解决的更多相关文章
- spring boot 集成mybatis报错Missing artifact
1. pom文件中的oracle依赖提示Missing artifact,需要手动下载并导入maven参考 oracle依赖下载地址 (ojdbc6.jar) cd到下载的ojdbc6.jar所在路径 ...
- spring boot 集成mybatis报错
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of ...
- spring boot中连接数据库报错500(mybatis)
spring boot中连接数据库报错500(mybatis) pom.xml中的依赖 <!-- 集成mybatis--> <dependency> <groupId&g ...
- spring boot 启动遇到报错:Failed to configure a DataSource
spring boot 启动遇到报错,具体如下 Description: Failed to configure a DataSource: 'url' attribute is not speci ...
- 【spring cloud】spring cloud集成zipkin报错:Prometheus requires that all meters with the same name have the same set of tag keys.
spring boot 2.0.X 的版本,整合zipkin2.10.1 zipkin服务启动后,访问zipkin的UI http://localhost:8002/zipkin/ 页面显示空白,cs ...
- 创建spring boot项目启动报错遇到的问题
1.Spring boot,Mybatis 启动报错 Failed to auto-configure a DataSource *************************** APPLICA ...
- Spring boot临时文件目录报错
基本的错误信息如下: 2018-03-05 at 15:12:03 CST ERROR org.apache.juli.logging.DirectJDKLog 181 log - Servlet.s ...
- 【spring boot Mybatis】报错:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.newhope.interview.dao.UserMapper.add
报错如下: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.newhope.i ...
- Spring Boot整合Mybatis报错InstantiationException: tk.mybatis.mapper.provider.base.BaseSelectProvider
Spring Boot整合Mybatis时一直报错 后来发现原来主配置类上的MapperScan导错了包 由于我使用了通用Mapper,所以应该导入通用mapper这个包
随机推荐
- Python和JavaScript间代码转换4个工具-乾颐堂
Python 还是 JavaScript?虽然不少朋友还在争论二者目前谁更强势.谁又拥有着更为光明的发展前景,但毫无疑问,二者的竞争在 Web 前端领域已经拥有明确的答案.立足于浏览器平台,如果放弃 ...
- Ps中的难点问题分析
一.布尔运算的运用 1.布尔运算是在图形工具组中使用,快捷键“U” 2.使用方法:都是在同一图层下运算,在进行布尔运算之前,首先用路径选择工具,小黑箭头,快捷键是“A” 选取你要运算的图形. 3.布尔 ...
- oracle 新建数据库 ,新建用户
net manager 数据库名----电脑名localhost 1521 , 服务名 orcl (oracle 版本不一样, 不同版本不一样,,) 然后测试.. sys 账号登录 新建用 ...
- hdu-1176(动态规划)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1176 思路:类似数塔问题, 从最后一秒开始考虑,每次这一秒的状态确定意味着前一秒的状态也已经确定,所以 ...
- 处理jQuery选择器中的特殊符号,如(、#等
前几天解决一个外网问题,客服反馈页面数据加载不出来,首先看一下服务端日志也没报错异常,自己测试了一下,在chrome的Console发现有js报错,原来是js报错导致的数据加载不出来. 调试了一番,发 ...
- BZOJ 1009 [HNOI2008]GT考试 (KMP + 矩阵快速幂)
1009: [HNOI2008]GT考试 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 4266 Solved: 2616[Submit][Statu ...
- 01-html和head介绍
一.web标准 web准备介绍: w3c:万维网联盟组织,用来制定web标准的机构(组织) web标准:制作网页遵循的规范 web准备规范的分类:结构标准.表现标准.行为标准. 结构:html.表示: ...
- linux上安装maven
解压安装: tar -zxvf apache-maven-3.3.9-bin.tar.gz 配置环境变量 cd /etc/ vi profile 在最后面加上M2_HOME=/usr/local/my ...
- UCMap移动GIS & 时空地图GIS
UCMapViewer是基于UCMap(OpenGL版)的通用地图开发框架,涵盖了各类GIS数据的展示.查询.编辑.分析等各项功能 (http://www.creable.cn/kuibu/xiaza ...
- java基础-day1
第01天 java基础知识 今日内容介绍 u Java概述.helloworld案例 u 工具安装 .配置环境变量.注释.关键字 u 常量.变量.数据类型.标识符 第1章 Java概述 1.1 ...