开发踩坑记录,不定时更新
心得
- RTFM
- 严谨的去思考问题,处理问题
- 严格要求自己的代码编写习惯与风格
- 注意 单词拼写
20200207 mybatis plus 自带insert插入异常 sql injection violation
解决方法:
使用逆向工程脚本时,生成的映射实体类在下面的注解会多table:
删除即可
@TableName(“table:ts_app_oracle_apply”)
20200209 数据库字段自动更新生成问题
异常描述:更新数据时,个别时间字段没有进行更新,但是更新操作执行完成后,不该被更新的字段更新了
解决方法: 数据库中,设计表,修改所有时间字段,根据当前时间戳更新,关闭该选项
20200210 中文乱码问题
详细信息:java后台使用content-disposition属性返回中文文件名时,出现编码问题 urlencode编码,需要前端解码
access-control-allow-credentials: true
access-control-allow-headers: Origin,X-Requested-With,accept,content-type
access-control-allow-methods: OPTIONS,GET,POST,DELETE,PUT
access-control-allow-origin: *
content-disposition: attachment;fileName=%E5%A4%A9%E5%B1%B1%E5%B9%B3%E5%8F%B0%E7%94%A8%E6%88%B7%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E8%B5%84%E6%BA%90%E7%94%B3%E8%AF%B7%E5%AE%89%E5%85%A8%E8%B4%A3%E4%BB%BB%E6%89%BF%E8%AF%BA%E4%B9%A6.docx
content-type: application/force-download
date: Mon, 10 Feb 2020 03:11:46 GMT
transfer-encoding: chunked
20200210 指定配置文件启动
指定配置文件启动命令失效,与启动脚本与jar包同级目录下,建立config文件夹,存放配置文件在其中,
即可指定外部配置文件启动
20200216 文件删除失败
原因:没有关闭对应输入流
20200218 excel文件导入,将数据返回时出现空指针异常
经检查,发现是两张表excel中,某个字段名不一致导致
20200224 应用上线前端按钮无法显示
原因:在后台的逻逻辑判断时,只考虑了应用申请记录不为空的前提,当应用为空的时候
控制按钮的值就无法赋值,导致了前端控制按钮的值为null
解决:修改判断逻辑
20200224 nginx代理静态资源问题
原因:在nginx代理时,需要用到静态资源,静态资源的目录是从根目录也是就是“/”开始的
n那么,在配置代理时,location后就不能带有前缀或者后缀,只能以“/”开始的
当然也不是绝对,要考虑实际的静态资源的状态,去配置代理
20200224 nginx代理cas登录问题
现象: 在使用nginx代理时,发现登录的cas模块会跳到代理机ip+端口的地址,不会跳到代理地址
原因: 前端代码在写登录时,直接使用本地地址作为登录地址,所有要想到正确的登录地址,需要进行代理,才可以
20200225 文件上传出错
原因:文件上传直接报错,其实文件是上传成功的,但是由于数据库的某个字段不能为空,导致程序异常
返回错误码,直接显示文件上传失败
20200303 数据库连接异常
要注意部署数据库的环境与服务环境是否相同
20200314 接口请求异常
测试环境接口可以正常请求,但是正式环境无法请求,原因是正式环境无法直接请求正式环境对应接口,加了
20200316 ftp连接关闭
查看代码时,突然发现ftp连接后没有关闭,虽然ftp会自动关闭,但是连接过多时不关闭会对资源产生影响
20200317 无法删除压缩包文件
没有关闭压缩包文件对应的流
20200318 调用webservice接口失败
没有对接口地址
20200320 数据库连接异常
忘记配置端口
20200320 文件夹创建解析异常
linux中的文件符为/,windows中的文件符为\,要注意区分
20200324 h2数据库查询异常
在使用轻量数据库h2时,发现插入数据正常,但是查询数据会报错,会将插入的string字符串,强制转换为int类型
检查后发现,h2数据表的字段顺序与实体类中的字段顺序必选保持一致,否则会出错
20200408 postwoman请求异常
使用postwoman时,接口无法正常请求测试,但通过swagger可以正常测试使用
定位后发现postwoman是使用XMLRequest发送请求,需要在后台代码中设置跨越处理
20200420 ftp文件导出异常
用户上传文件后无法导出下载的问题,检查后发现代码没有判断非空选项值,且ftp目录权限存在异常,已经修复
20200421 redis数据获取异常
redis数据库中有对应的值,但是在代码中无法获取,调试后发现是序列化原因,代码发送取值请求时,key的序列化与redis的序列化
不一致,所以获取值失败
20200421 控制台日志打印异常
pom依赖存在冲突
20200421 mongoDB配置异常
在项目中没有使用到mongoDB的任何依赖,但是运行时抛出了没有配置mongoDB的异常
原因是在项目中使用了jmeter的依赖包,而jimter依赖包会使用MongoDB的依赖
maven在解决依赖时,会自动解决传递依赖,所以会自动引入mongodb的依赖,导致运行异常
只需要在启动类中添加排除注释即可
也可以在.iml文件中,搜索MongoDB的依赖,删除即可
20200422 mybatis pluse 映射类构造异常
在mybatis plus的映射构造类中,使用了lamlok时,会自动建立无参构造
但是如果在构造类中手动建立了构造函数,那么mybatis在执行自带查询时,结果返回会自动使用建好的构造函数
会导致返回值无法返回的异常
20200422 json数据二次转义问题
解决办法就是,只转一次。转两次就会出现这个情况,你可以把之前转的json转成map
20200509 jmeter使用java调用接口参数传递异常
场景
再使用java代码调用jmeter的接口去发送post请求时,发现json字符串会被转义
即双引号,大括号之类的特殊符号会被转义
涉及到的类为 HTTPSamplerProxy类与SampleResult类
HTTPSamplerProxy类设置请求参数,接口地址端口请求头等信息
SampleResult类用来发送请求,并接收返回结果
但是在HTTPSamplerProxy参数传递的过程中并为发现字符转义
在SampleResult发送请求时,json字符串被转义,涉及方法为queryString方法
解决方法:
经调试发现,参数转义步骤,检查为什么会执行转义
可能性猜测为.
HTTPSamplerProxy添加请求参数时,使用的形式为key:value形式,当请求参数也为键值对形式时
不论是post还是get,参数都会被拼接到url接口地址的后面,所以再使用SampleResult发送请求时
url中的特殊符号会全部被转义
所以当参数为json字符串类型,且位于body时,不用添加参数的key,直接将值添加到HTTPSamplerProxy实体中即可
疑问点
1:参数位于query时,且参数为json字符串时,如何避免转义?
此时必须转义,否则报错,目前只发现可以手动转义
20200518 服务启动正常,但是接口调用时抛出类找不到的异常
代码无异常,配置文件无异常。
接口请求就异常
swagger-ui无法访问
本地启动服务无异常
经检查:发现启动项目的用户权限异常
设计启动用户为adcloud
实际启动用户为root
使用自动化发布工具部署发布时,使用的是adcloud用户
导致权限不够,无法读取依赖包,抛出类加载异常
20200521 Apache错误:[error] (OS 10038)在一个非套接字上尝试了一个操作
解决办法一:
可能是安装了某些程序修改了Winsock,使用netsh winsock reset 命令修复Winsock重启计算机即可!
解决办法二:
在httpd.conf文件中添加 Win32DisableAcceptEx 标记,如下:
< IfModule mpm_winnt.c>
ThreadsPerChild 1000
MaxRequestsPerChild 10000
Win32DisableAcceptEx
</IfModule>
解决办法三:
1、网上邻居-;本地连接-;属性-;internet协议(TCP/IP)-;属性-;高级 -;wins标签-;去掉启用LMhosts查询前的勾.
2、控制面版-;windows防火墙-;高级标签-;本地连接设置-;服务的标签里勾选安全Web服务器(HTTPS)。
3、然后重启Apache
20200522 添加eureka-server服务异常
springcloud更新换代比较快,可能1.5可以使用,到了2.0就不用了。所以做项目或者练习时要看清自己使用的版本。
1.5版本使用spring-cloud-starter-eureka-server还是没问题的。
2.0以上建议使用 spring-cloud-starter-netflix-eureka-server。
20200522 spring cloud 项目eureka client端启动异常 Completed shut down of DiscoveryClient
添加spring boot web依赖后解决
20200522 @Autowired注解与@Resource注解的区别
:@Autowired只按照byType 注入;@Resource默认按byName自动注入,也提供按照byType 注入;
20200522 Eureka异常 EMERGENCY! EUREKA MAY BE。。
警告!Eureka可能存在维护了错误的实例列表(当它们没有启动的时候,Eureka却把它当成启动的了)
;Renews值小于Threshold值,因此剩下未过期的都是安全的。
原因:
这个是Eureka的自我保护机制。Eureka Server在运行期间,
会统计心跳失败的比例在15分钟之内是否低于85%,如果出现低于的情况(在单机调试的时候很容易满足,
实际在生产环境上通常是由于网络不稳定导致),Eureka Server会将当前的实例注册信息保护起来,同时提示这个警告。
解决方案
1、在生产上可以开自注册,部署两个server
2、在本机器上测试的时候,可以把比值调低,比如0.49
3、或者简单粗暴把自我保护模式关闭
20200602 Long类型异常
再生成六位验证码时,此处的验证码类型为long类型,不是String类型
发现会有小概率产生的验证码位数不对,由六位变为五位,且数值也与六位的数值不一样
类举排查后发现:
long类型的数据,以0开头时,会出现位数变化,即下边的情况
Long errNum = 012345L;
此时 errNum的值为10024
原因是在Java语言中
数值类型的数据:
0开头表示八进制
0x开头为十六进制
20200605 mybatis插入数据异常
表中字段为int,自增
实体类设置为了uuid导致异常
且数据表中字段对应差一个分隔符
20200620配置文件路径异常
再使用方法时,.class.getClassLoader().getResource(“jmeter.properties”).getPath();
获取到的配置文件路径为全路径,即绝对路径
不是相对路径
打包为jar包时,获取的路径为jar包路径,上述方法获取到的路径,无法直接获取到配置文件
导致程序异常。
20200703 线程对象问题
线程池里用传递的方法,不会导致新建对象,占用内存
用new的方式才会有很多 线程里面传进去的应该是同一个实例
20200703 try,catch,finally
当三者配合使用时,及时try中进行了return,finally中的语句还是会执行
20200708 mysql插入异常
字段不能使用mysql中的保留字段,如function,delete等关键字
20200709 mybatis plus 注解自定义sql时,函数返回值尽量使用包装类
20200717 mybatis plus查询异常
实体类若自定义构造后,没有生成空参构造,查询字段会出现异常,导致无法将值赋予对应字段
20200727 idea全局搜索异常
快捷键 :Ctrl+Shift+F 步骤:设置 -->时间和语言–左侧的语言–>点击语言模块下的"中文(中华人民共和国)"
–>点击“选项”–>点击键盘模块下的“微软拼音”–>选项–>点击“按键”–>最下面的“热键”–>简体/繁体中文输入切换
20200805 mybatis plus IPage分页异常
使用IPage方法进行分页查询时,必须要将IPage参数放到自定义方法的第一个参数位置
否则会报异常,select one but found many;
20200805 elasticSearch无法使用root用户启动
20200805 mybatis plus 查询异常
在mybatis mapper接口类中,方法不能重载
/尚未解决/
20200811 elasticSearch建索引-表异常
使用自定义json字符串,可以成功建表
使用hashMap转成的json字符串,无法建表,
原因不明:
1:猜测hashmap无序,导致字段顺序异常?
20200902 mybatis plus拼接sql异常
字段为空时,使用mybatis plus自带的.eq()方法查询时,
会变成查询全部
20200831
1、spring boot切面aop使用多个 websocket会二次发送
2:linux中特殊字符^M,是应用windows下的回车
20200902 h2数据库初始化异常
在spring boot中,使用h2本地数据库+mysql数据库配置俩个数据源时
遇到了h2数据表初始化异常,无法建立h2数据表
且建表语句无异常,配置文件无异常
经排查发现:
配置yml文件中,自定义多个数据源,h2无法识别
只能在.properties文件中,优先使用spring.datasource.driver-class-name的方式配置h2
然后再去yml文件中配置数据源,这样h2数据源就会先初始化,不会导致建表语句无法执行
20200909 mybatis分页没有生效
使用mybatis中自带分页,并配置了分页拦截
/**
* mybatis-plus分页插件<br>
* 文档:http://mp.baomidou.com<br>
* 需要注意的是Page参数需要放在参数列表的第一个
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
但是实际使用中,却没有生效,需要在数据源配置类中加入以下代码
``@Bean(name = "viewSqlSessionFactory")
public SqlSessionFactory sqliteSqlSessionFactory(@Qualifier("viewDataSource") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.addInterceptor(new PaginationInterceptor());
sqlSessionFactory.setConfiguration(configuration);
sqlSessionFactory.setDataSource(dataSource);
return sqlSessionFactory.getObject();
}
20200921 拦截器write.print返回字段异常
writer.print()方法不能直接打印错误对象,需要将对象转化为JSON字符串,才可以返回,否则返回的为对象的内存地址。
20201027 spring boot注解@Autowired异常
现象:在开发过程中,突然方法中的String类型参数会被提示没有String的bean,无法注入
后续发现是方法上误加了@Autowired注解导致
20201027 spring cloud消息总线配置异常
场景,使用spring cloud的微服务网关功能注册api时,发现注册的api无法访问,
数据库中与gitlib中已经新增了新建的api的相关信息与路由
排查问题:数据库与gitlib中都有信息,即新增操作已经成功
调用api时提示没有该api路径,网关服务与配置中心服务都运行正常
查看日志发现配置中心无法连接kafka服务,发现kafka服务崩溃,重启kafka
依然无法解决;
查看配置文件,发现springcloud消息总线配置有问题,修改配置文件后重启服务;
接口可以通过网关注册并发现。
spring cloud消息总线中对应关系需注意,且需注意分组配置
20201027 green plum执行查询sql异常
green plum sql语句与mysql在使用limit语句有些许不通
mysql : select from table limit begin,size
green plum : select from table limit size offset begin
调用post接口传参异常
在调用别人开发post接口时发现,传递的参数放到body中,始终无法成功调用
会提示必选参数没有传递,经沟通发现该接口虽为post类型,但参数接收并没有采用body
接收参数,且在接口定义中使用@RequestParam接收参数,即只能将参数拼接到api接口地址后
才可成功调用api。
20201102 mybatis plus启动异常
org.apache.ibatis.builder.BuilderException: Could not find value method on SQL annotation. Cause: org.apache.ibatis.builder.BuilderException: Parsing error was found in mapping #{}.
Check syntax #{property|(expression), var1=value1, var2=value2, …}
其实就是#{}里面没有写参数。。。
20201104 swagger-ui接口测试异常
使用spring boot集成swagger-ui进行接口测试时,发现新定义的接口无法在swagger-ui中进行测试
网页控制台js输出找不到Content-Type,其他接口均使用正常
经过调试后发现,接口有一参数名为nodeType,该参数名在swagger-ui中被认为是保留字段,会被解析
导致接口无法正常调用,本次场景出现使用的swagger-ui的版本为2.6.1,在2.9.1中未遇到该问题
20201106 ftp文件下载异常
搭建好新的ftp服务器,
使用java进行ftp文件操作时,发现文件可以正常上传,但是无法正常下载
每次下载
20201110 循环依赖
在spring boot框架中使用JDBCTemplate连接数据库时,两个DAO层存在了循环依赖,导致项目无法启动
20201116 lua脚本问题
由于对lua脚本语言不是很熟悉,在nginx中使用lua脚本语言时,先使用了ngx.say的方法
然后进行业务逻辑处理, 导致后续业务逻辑无法执行,并且抛出异常,注释ngx.say后,
该问题消失,原因可能是lua脚本的执行顺序可能有比较严格的规定。
20201119 mysql连接问题
在使用omindb连接数据库时,发现无法连接mysql8.0以上的数据库
后续调整了mysql8.0的服务认证方式之后,可以连接
是因为新5.7与8.0的密码加密方式不通
20201214 javamail smtp邮件发送异常
配置后无法正常发送,抛异常如下
JavaMail Exception: javax.net.ssl.SSLException:
Unrecognized SSL message, plaintext connection?
经搜索排查后,修改配置文件如下:
Properties props = new Properties();
props.setProperty(“mail.smtp.auth”, “true”);
props.setProperty(“mail.debug”, “true”);//启用调试
props.setProperty(“mail.smtp.starttls.enable”, “true”);//添加这个
props.setProperty(“mail.smtp.ssl.enable”, “true”);
props.setProperty(“mail.imap.socketFactory.fallback”, “false”);
//不需要这个
//props.setProperty(“mail.imap.socketFactory.class”, “javax.net.ssl.SSLSocketFactory”);
原因尚不明确,需继续排查,可能是如下原因
配置JavaMail的Properties时,不要指定“mail.smtp.socketFactory.class”,因为TLS使用的是普通的Socket。
然后指定属性“mail.smtp.starttls.enable”为“true”。
20201214 nginx代理异常
再使用nginx二级目录方式代理多个不同项目时,出现了静态资源404的问题
经排查后发现是不通项目中文件资源路径的问题
只能使用单端口代理单服务,不会出现该问题
20201214 jpa实体类参数问题
在使用jpa自定义sql查询,映射实体类时,
当使用的语句是*
时,要注意数据库中的表字段与实体类中的字段顺序是否一致
不一致会出现类型映射异常
20201216 maven打包异常
场景:更换maven配置文件后,使用maven打包项目,抛出异常,无法识别字段
但是项目中所有依赖均无报错,清除缓存后也可本地正常启动,只是打包无法打包
会提示一系列异常
排查:在处理该问题时,百度了很多方法,均未生效,将原有maven本地仓库删除,重新导入
依赖,也没有任何作用,还原配置文件,也没有作用,发现idea中配置好后maven,使用
右侧工具栏的maven插件,可以编译打包,但是命令行打包依旧失败
在配置IDEA中maven路径时,发现有IDEA自带maven配置,问题可能出现在这里
尝试解决: 打开IDEA默认maven配置路径,发现在C盘用户名下的.m2文件夹内,依旧有一个maven
配置文件,该配置文件中的配置为默认配置,可添加公网依赖,但是无法添加内网依赖,
修改该配置文件后,打包正常
可能原因: 命令行使用maven打包命令时,读取配置文件的顺序可能是这样的:
maven安装目录配置-》系统自带maven配置
即C盘下的配置文件,优先度可能高于安装目录的配置文件
这样就导致在IDEA中配置好后maven,使用右侧maven工具插件可以打包,因为IDEA会去读
项目配置好的,而不去读系统默认的
但在命令行中,会使用系统变量中的maven,读取配置文件的顺序也如上所述,所以导致无法打包
20201218 swagger-ui模型绑定异常
场景:在srping boot中使用swagger2.9.2时,接口参数定义类型为Double
在启动时会报异常 databind error
解决:排查后发现是swagger2.9.2中自带的swagger-models存在bug,需要单独导入
导入方式如下,即可避免数值类型的参数绑定异常
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>
20201218 maven打包的jar包运行正常,但是调用接口时,接口抛异常
场景:本地IDEA中运行,调用接口无异常,本地打包后,运行jar包,提示com.sun.**类不存在
排查:检查jdk中的jre是否缺少该jar包,发现缺少,复制jdk中的tool.jar,重新打包,问题存在
有博客说是因为jdk1.8打包时会排除jdk1.5的com.sun的包,估修改pom配置文件如下
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
<compilerArgument>-XDignore.symbol.file</compilerArgument>
<compilerArguments>
<bootclasspath>${env.JAVA_HOME}/jre/lib/rt.jar:${env.JAVA_HOME}/jre/lib/plugin.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
问题依旧存在,清除缓存,重新导入maven,清楚idea缓存,maven命令clean,update
均未生效,其他项目打包正常,唯独该项目存在这个问题
解决:迫于无奈,只能使用本地依赖的方式,pom中指定tool.jar包,问题解决
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${pom.basedir}/lib/tools.jar</systemPath>
</dependency>
可能原因:该项目使用了公司内部的frm框架,有部分frm框架jar包因业务不需要,去除后
出现了该问题,可能的原因去除的frm框架依赖包中有改tool.jar依赖,但是父依赖
依旧使用的frm依赖,即可能导致maven认为该项目不需要导入tool.jar,导致依赖丢失
本地运行时正常,运行时可能使用了本地jdk中的依赖,所以不会报错,真正原因尚未定位。
20210301 maven打包问题
在IDEA中配置好maven后,依赖添加正常,项目运行正常,使用IDEA自带打包插件也可以打包
但是在命令行中打包异常,无法打包,会提示很多error信息
经排查后发现,maven在命令行执行打包时,默认读取的配置文件是settings.xml,而不是IDEA选择的配置文件
修改settings.xml配置文件后,打包正常。
20210301 关于spring boot配置文件问题
spring boot打包的jar包启动时,可以指定配置文件启动,但是直接使用java -jar的方式使用外部配置文件时
指定的配置文件仅有application.properties 和xx.yml
20210301 ansible接口调用异常
在使用python调用ansible接口时,抛出了psutil依赖找不到的异常
排查发现,我安装的ansible版本为2.9.16,默认支持的python2
环境里安装的python是python3,pip3安装时将依赖安装到了python3
使用pip安装后正常
20210316 greepplum数据库查询异常
在查询greenplum数据库时,遇到这样一个问题,同一个表 select * from "TEST"
可以正常查询,但是使用select * from test
就无法查询,提示表不存在,表名是不区分大小写的,查找资料后发现是建表语句的问题,在建表,表名增加了双引号,导致查询时必须使用和双引号内部一样的表名,如下图论坛中的回复所示
20210325 代码排序异常
排序代码如下,查询数据库,然后格式化时间,根据时间进行排序
但是数据库中的数据存在一样的时间,就导致了排序异常,逻辑互相冲突,修改时间后再无异常出现
SimpleDateFormat inSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Collections.sort(list, (o1, o2) -> {
try {
if (inSdf.parse(o2.getAllocateTime()).getTime() >= inSdf.parse(o1.getAllocateTime()).getTime()) {
return 1;
}
} catch (ParseException e) {
e.printStackTrace();
return -1;
}
return -1;
});
20210618 上述bug又出现了,排序异常,还是相同的问题,没有考虑到相等的情况,每次修改数据库的行为并不可取,开始排查,原因就是没有考虑到俩个元素相同的问题,导致出现了异常,后来采用.compareTo()方法后,异常解决
看源码后发现,源码是多了一个等于情况的判断,所以就没有了异常
public static int compare(long x, long y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
20210412 mybatis删除无效bug修复过程记录
场景:webservice接口无法正常删除不需要的用户信息
排除过程
1:检查业务逻辑,业务逻辑无异常
2:因存在计数器统计删除计数,怀疑为多线程导致,加锁后,依旧无法删除
3:传参问题,参数传递无异常
4:mybaits参数传递问题,排除,参数传递正常
5:逐句分析代码作用与逻辑,发现漏洞,码的智障,查询出的id没有赋值,淦
20210531 elasticSearch聚合索引查询异常
在使用java代码去查询es时,若es的索引无数据,会报404异常
20210532 elasticSearch聚合索引查询排序异常
场景:
在使用java代码去查询es时,对日期类型的字段进行排序,发发生了排序异常,无法排序
异常排查:
1、测试环境所使用es版本为7.2,修改该字段类型为keyword,可以排序
2、生产环境使用es版本为7.4,修改字段类型为keyword,无法排序,修改为类型为date,还是无法排序
解决方案:
1、在java查询代码中给字段加了.keyword,后缀后,可以进行排序查询,但还不是真正的无法排序的原因
builder.sort("pushTime.keyword", SortOrder.DESC);
2:查es中的mapping配置后发现,定义的数据类型与模板不一致,经排查后发现,建立索引时使用了索引模板
3、索引模板中的index_patterns字段必须要和索引名称一致,这样建立的索引,才会使用该索引模板
即数据类型会使用模板里的数据类型
4、index_patterns是索引模式,指当创建以index*
开头的索引时,使用该索引模板。
注意,在elasticsearch的6.x版本中,索引模板模式index_patterns取代原来的template。
索引模板信息可参考下面的文章
https://www.cnblogs.com/Neeo/articles/10869231.html
20210621 mybatis-plus多数据源配置异常
一直在使用的mybatis多数据源配置,迁移到新项目中,突然无法生效了,只会去查询第二个数据源的数据库,导致很多业务逻辑无法跑了,配置多数据源的方法比较简单,直接两个配置类进行配置,一个类配置一个数据源,指定一个数据源为主数据源
配置内容就更简单了:主数据源
从数据源与主数据源内容基本一致,只需去除primary主机,并修改相应类名即可,但是,突然不生效了,就是无法查询,找了很多方法,都不行,后来注意到,从数据源中少了句代码,就是下面的这句:
因为少了这句代码,spring在进行数据源初始化时,会把MybatisConfiguration这个配置文件初始化两次,即从数据源配置会覆盖主数据源配置,导致查询异常。。。。
20210719 hashMap值修改未生效问题
hashMap存入时会先获取key的hash值,
调用putVal方法,传入key的hash值,key,value,
在该方法内部,会将传入的hash值与已有hash值进行比较,
简单看了下源码,如简单遍历ArrayList<HashMap<String,String>>,
取出值并修改后插入新的ArrayList时,值修改可能会失效,个人理解可能存在差异
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
//建立节点tab,p,定义临时变量n,i,table为第一次使用时初始化的hashtable
Node<K,V>[] tab; Node<K,V> p; int n, i;
//获取hash表长度
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//取出hash值,与新值比较,不存在则插入新的节点
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
//存在,则进行hash值比较判断,K为当前hashmap的key
Node<K,V> e; K k;
//如果传入的key的hash值与key值与已存在的key相等且不为空,为节点e赋值
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
//左边的对象是否是它右边的类的实例,返回 boolean 的数据类型
//此处判断p是否存在与当前hashMap的TreeNode中
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
//都不存在时,开始遍历已有集合,进行判断插入?
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
//已存在,判断值是否需要替换
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
//容量增加,判断容量是否增加?自动扩容?
++modCount;
if (++size > threshold)
resize();
//节点之后插入
afterNodeInsertion(evict);
return null;
}
20210830 es数据插入异常
在往es里插入数据时,发现新接入的日志数据无法正常插入,且只有极少数的日志可以插入;
开始排查业务代码,发现业务代码并没有问题,数据也可以正常读出,但是无法插入;
将服务部署在服务器上时,也无法插入,且没有任何异常信息,
于是开始对比新旧日志的区别,发现旧的日志数据中,有一个时间字段格式为 yyyy-MM-dd HH:mm:ss ,但是新日志的该字段数据格式为 yyyy-MM-dd HH:mm:ss.SSS,在建立es字段索引时,已经约束了该字段格式只能是yyyy-MM-dd HH:mm:ss,所以新日志数据无法插入。
20210923 spring boot中this方法调用导致aop失效
在使用AOP去对某些方法的返回值做处理时,发现一个问题,
使用this的方式去调用方法时,该方法的返回值不会被aop处理,
使用注解,代理生成自身对象后,再调用该方法,返回值被AOP处理;
至此,问题结束,但是没有考虑为什么this调用的方式不会被AOP处理。
疑问:那么为什么this的aop会失效呢?
在看了一大堆大佬的文章后,发现最终结论,过程比较复杂,有兴趣的可以去看一下
结论如下:
1、spring中,非动态代理生成的对象,不会被aop捕捉;
2、因为AOP动态代理的方法真实调用,会使用真实被代理对象实例进行方法调用,
故在实例方法中通过this获取的都是被代理的真实对象的实例,而不是代理对象自身。
参考链接:
csdn: https://blog.csdn.net/qq_33589510/article/details/120387044
oschina: https://my.oschina.net/guangshan/blog/1807721
20211028 docker容器启动即退出
若dockerfile中没有CMD去执行运行命令
打出的镜像包是直接运行不起来的
需用docker run 镜像 启动命令
这种方式进行容器启动
若带CMD,且CMD中的命令是一直与终端有交互的
打出的镜像包可以直接启动运行
此方式可以不启动任务程序运行容器镜像
docker run -d -p 9400:8100 镜像名 bash -c 'while true; do echo week;sleep 60; done ’
20211028 python项目启动
最近业务有涉及到python项目的启停问题,总结如下
django项目运行方式
****此命令需要在django项目所在文件夹执行
nohup python3 manage.py runserver 0.0.0.0:8100
flask项目启动方式,此处使用了gunicorn
****此命令需要在flask项目所在文件夹执行
gunicorn app:app -c gunicorn.conf.py
gunicorn.conf.py 配置文件 配置启动进程数,端口
workers = 5 # 定义同时开启的处理请求的进程数量
worker_class = "gevent" # 采用gevent库,支持异步处理请求
bind = "0.0.0.0:8888" # 端口绑定
项目停止脚本
此命令基本适用于单服务停止
kill -9 `lsof -i:启动端口 | awk 'NR==2{print $2}'`
20211229 mysql锁库
中午的时候,正式环境的数据库突然被锁库,导致数据无法更新
开始进行排查,经资料搜索后,发现这些信息都存放于information_schema库中
可以用下面三张表来查原因:
innodb_trx ## 当前运行的所有事务
innodb_locks ## 当前出现的锁
innodb_lock_waits ## 锁等待的对应关系
一张一张的去进行查询,发现长时间处于RUNNING的任务时
在mysql命令行中 使用kill 任务id 即可杀死进程 解除表锁,业务恢复正常
注:此处的id常为一串数字,可多次进行尝试
产生锁库原因时某一sql运行时间过长,导致整个mysql库被锁,其他位于该服务库的库全被锁
附上参考链接:
https://blog.csdn.net/weberhuangxingbo/article/details/88709556
20220106
乐观锁
额外增加字段,时间戳,版本号之类的标志,取数据时要带着版本号
更新数据时,如果库内版本号与传入一致,则更新,否则不更新
悲观锁
查询出要更新的数据,然后加for update ,这样不提交,其他也无法修改
select…for update
20220109 nginx反向代理端口丢失
情况如下:
源主机Aip地址为:10.0.0.1:30001
代理B主机地址为: 120.0.0.1:30002
现在在B主机上使用nginx代理A主机的30001端口
直接访问B主机的30002端口,可访问到被代理的主机A的30001端口
但刷新浏览器之后,代理端口丢失了,就会跳向B主机的30001端口
导致访问异常,代理配置均无问题,其他几十台代理端口均正常
唯有代理出来的A不正常,怀疑是代理端口丢失
只能保证源端口和代理端口一致
具体原因未明。
20220215 日志文件太大无法直接查看处理
今天遇到一个问题,需要看日志文件才能定位到具体原因
但是一看日志,有七八个G。。。。使用常用的tail -n 或-f无法定位到
但是整个文件又太大,操作起来很不方便,无法快速定位到异常
可以使用下面的组合命令,导出自己想要的大概日志范围
查看日志文件有多少行:wc -l 文件名
将目标文件指定行数导入到新文件(p为参数,必选):sed -n “开始行,结束行p” 目标文件 > 输出文件
20220222 记一次数据采集延时导致数据丢失问题问题
问题:
现有A,B,C,D四个平台的api日志信息需要采集到es中;
入库es后,定时任务采集统计调用信息,入库mysql;
但运行一段时间后发现,mysql中统计的数据量远远小于es中存储的数据条数;
且采集程序与统计程序均无异常日志;
经排查后发现是数据延时问题:
现象如下:
A 批数据 入库时间字段为14:00 真实入库时间为14:00
B 批数据 入库时间字段为13:53 真实入库时间为13:53
C 批数据 入库时间字段为14:03 真实入库时间为14:06 存在延迟
D 批数据 入库时间字段为14:04 真实入库时间为14:04
1、定时任务开始统计上面的数据,入库mysql,并记录最新入库时间到redis,
2、作为下一次查询es的开始时间范围
3、当A,B,D的数据被查询统计时,C的数据还没有入库,但入库时间字段为14:03
4、统计程序记录的最新入库时间字段已经是14:04了,那么C的数据就会丢失;
5、长久以往,丢失数据会很可观,
解决方式:
延迟统计时间(如果对实时性要求不高),
若定时任务五分钟统计一次,如14:00开始查询es统计入库mysql,统计延时十分钟;
查询es的入库时间范围就是 13:45:00 ~ 13:50:00
这样就可以尽可能避免延时区域过小导致的数据丢失问题
20220224 Jenkins接口调用
1、首先需要在用户管理-》用户设置-》生成api token;
2、然后系统管理-》全局安全配置-》关闭CSRF Protection选项(防止跨站点请求伪造)
3、然后去项目配置-》Build Triggers-》Trigger builds remotely (e.g., from scripts)-》填入token名称
4、postman中调用方式为http://登录用户名:3中的apitoken@ip:port/需要调用的api接口
20220301 mybatis-plus重载异常
傻叉错误,好久没遇到了,自己把自己坑死了
mapper中有如下俩方法
findAllByDate(Page page,Integer status)
findAllByDate(Page page,Integer status,String content)
调用的时候,没有问题,点击的时候也是会跳到相应的方法
但是,有且只有一个查询方法生效,另一个改的天花乱坠都不会生效
目前发现最终执行的方法为第二个,即顺序执行最后一个
20220303 Jenkins接口调用403异常
最近业务需要对Jenkins进行一些操作,JenkinsServer可以对Jenkins进行一些操作
但是功能不适用,只能自己进行接口封装,去进行接口调用
但是有这样一个现象,使用postman可以对目标接口调用,curl也可以对目标接口调用
一使用代码去请求接口时,就是403,返回未认证,使用JenkinsServer,就正常,但是不满足业务需求
那么为什么JenkinsServer包装的就行,自己写的就不行?
解决思路:
1、先查询一下有没有人遇到相似的问题,发现都是基于修改Jenkins配置,此时修改了也解决不了,换思路;
2、开始看JenkinsServer的认证过程,一层层往里走,发现了它的认证方式,也是http请求,奇了怪了,为啥我的就不行
一点点看源码,终于理了出来,顺序如下:
最外层的认证:
JenkinsServer jenkinsServer = new JenkinsServer(new URI(rul), username, passwordOrapiToken);
往里一点,发现用的是JenkinsHttpClient,整一个出来,继续往里走,是下面这样:
JenkinsHttpClient jenkinsHttpClient = new JenkinsHttpClient(new URI(rul), username, passwordOrapiToken);
在往里走,用了个this(uri, HttpClientBuilder.create(), username, password);
继续往下走,发现了猫腻,在下面的方法他进行了一次认证,还加了一个BasicHttpContext;
这俩缺一个都不行,继续往下走,看是怎么认证的:
public JenkinsHttpClient(URI uri, HttpClientBuilder builder, String username, String password) {
this(uri, addAuthentication(builder, uri, username, password));
if (StringUtils.isNotBlank(username)) {
this.localContext = new BasicHttpContext();
this.localContext.setAttribute("preemptive-auth", new BasicScheme());
}
}
就是这个:
protected static HttpClientBuilder addAuthentication(HttpClientBuilder builder, URI uri, String username, String password) {
if (StringUtils.isNotBlank(username)) {
CredentialsProvider provider = new BasicCredentialsProvider();
AuthScope scope = new AuthScope(uri.getHost(), uri.getPort(), "realm");
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
provider.setCredentials(scope, credentials);
builder.setDefaultCredentialsProvider(provider);
builder.addInterceptorFirst(new PreemptiveAuth());
}
return builder;
}
整了半天才发现,它进行了basic认证。。。。
知道怎么处理的就简单了,把上边的方法整出来,放到自己写的请求代码中,同时设置BasicHttpContext,就ok了,附代码如下
package com.eastcom.zmcc.kasswebide.service;
import com.eastcom.zmcc.kasswebide.core.common.constant.JenkinsConstants;
import com.offbytwo.jenkins.JenkinsServer;
import com.offbytwo.jenkins.client.JenkinsHttpClient;
import com.offbytwo.jenkins.client.PreemptiveAuth;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
/**
* Author by huyuxiang
* Date on 2022/3/3 11:00
*
* @author hyx
*/
@Service
public class JenkinsService {
@Value("${jenkins.username}")
String username;
@Value("${jenkins.password}")
String password;
@Value("${jenkins.url}")
String requestIp;
private static final Logger logger = LoggerFactory.getLogger(JenkinsService.class);
/**
* 此方法为接口认证方法,此处适用于Jenkins中进行接口校验
* 否则Jenkins接口无法,均为403
*/
protected HttpClientBuilder addAuthentication(HttpClientBuilder builder, URI uri, String username, String password) {
if (StringUtils.isNotBlank(username)) {
CredentialsProvider provider = new BasicCredentialsProvider();
AuthScope scope = new AuthScope(uri.getHost(), uri.getPort(), "realm");
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
provider.setCredentials(scope, credentials);
builder.setDefaultCredentialsProvider(provider);
builder.addInterceptorFirst(new PreemptiveAuth());
}
return builder;
}
protected String doGetWithAuth(String url, HashMap<String, String> param, HashMap<String, String> header) throws URISyntaxException {
HttpClientBuilder build = HttpClientBuilder.create();
build = this.addAuthentication(build, new URI(requestIp), username, password);
HttpClient httpclient = build.build();
//这一步非常重要!还是403
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute("preemptive-auth", new BasicScheme());
String resultString = "";
HttpResponse response = null;
try {
// 创建uri
URIBuilder builder = new URIBuilder(url);
if (param != null) {
for (String key : param.keySet()) {
builder.addParameter(key, param.get(key));
}
}
URI uri = builder.build();
// 创建http GET请求
HttpGet httpGet = new HttpGet(uri);
if (header != null && header.size() > 0) {
for (String key : header.keySet()) {
httpGet.setHeader(key, header.get(key));
}
}
// 执行请求
response = httpclient.execute(httpGet, localContext);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
return resultString;
}
} catch (Exception e) {
logger.error("[error] 请求异常",e.getMessage(),e);
}
return "";
}
protected String doPostWithAuth(String url, String json,HashMap<String, String> param, HashMap<String, String> header) throws URISyntaxException {
HttpClientBuilder build = HttpClientBuilder.create();
build = this.addAuthentication(build, new URI(requestIp), username, password);
HttpClient httpclient = build.build();
//这一步非常重要!还是403
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute("preemptive-auth", new BasicScheme());
String resultString = "";
HttpResponse response = null;
try {
// 创建uri
URIBuilder builder = new URIBuilder(url);
if (param != null) {
for (String key : param.keySet()) {
builder.addParameter(key, param.get(key));
}
}
URI uri = builder.build();
// 创建http post请求
HttpPost httpPost = new HttpPost(uri);
if (header != null && header.size() > 0) {
for (String key : header.keySet()) {
httpPost.setHeader(key, header.get(key));
}
}
//第三步:给httpPost设置JSON格式的参数
if(StringUtils.isNotEmpty(json)){
StringEntity requestEntity = new StringEntity(json, "utf-8");
httpPost.setEntity(requestEntity);
}
// 执行请求
response = httpclient.execute(httpPost, localContext);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
return resultString;
}
} catch (Exception e) {
logger.error("[error] 请求异常",e.getMessage(),e);
}
return "";
}
}
20220422 maven打包异常
使用下面命令抛出异常:
mvn package -Dmaven.test.skip=true
/Unknown lifecycle phase “.test.skip=true”./
改为:
mvn clean install package ‘-Dmaven.test.skip=true’
/根本原因是使用了shell,而不是cmd去执行命令/
20220426 swagger集成异常
现象:swagger-ui.html无法访问 抛静态资源异常
v2/api可以返回json,但是json格式不正确,经过了转义
处理:springboot 2.0后fastJson不生效,需增加以下代码
但是之前并未遇到该现象,为什么产生该现象,暂时不明
//时间格式化
static String DATE_TIME_STR = "yyyy-MM-dd HH:mm:ss";
static DateTimeFormatter DATE_TIME_FORMATTER;
static String TIME_STR = "HH:mm:ss";
static DateTimeFormatter TIME_FORMATTER;
static {
DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_STR);
TIME_FORMATTER = DateTimeFormatter.ofPattern(TIME_STR);
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//springboot 2.0后fastJson不生效,需增加以下代码
converters.removeIf(converter -> converter instanceof MappingJackson2HttpMessageConverter);
//自定义配置
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, source) -> {
if (source == null) {
return "";
}
if (source instanceof LocalDateTime) {
String format = DATE_TIME_FORMATTER.format((LocalDateTime)source);
return format;
}else if(source instanceof LocalTime) {
return TIME_FORMATTER.format((LocalTime)source);
}
return source;
});
// 处理中文乱码问题
List<MediaType> fastMediaTypes = new ArrayList<>();
fastMediaTypes.add(MediaType.APPLICATION_JSON);
fastConverter.setSupportedMediaTypes(fastMediaTypes);
fastConverter.setFastJsonConfig(fastJsonConfig);
converters.add(fastConverter);
}
20220426 ffmpeg截取3gp视频异常
异常如下:写的比较清楚,当前安装的ffmpeg不支持3gp文件截取
需要为已安装好的工具重新添加插件,或者直接更新,使用新版本
Automatic encoder selection failed for output stream #0:1.
Default encoder for format 3gp (codec amr_nb) is probably disabled. Please choose an encoder manually.
可以参考下面的方式处理:
https://blog.csdn.net/weixin_35649605/article/details/117344981
20220428可运行的jar包,和给别人用的依赖jar包,哪里不同?
1、pom中不同,可运行jar包会有build标签,依赖jar包则没有
20220505 nacos配置读取异常
使用了nacos作为配置中心,IDEA中运行正常
打包后本地运行异常,项目启动时没有去读取nacos中的配置
分析原因,nacos读取配置文件默认使用UTF-8,通过cmd启动项目,项目默认编码格式为GBK,导致问题出现
解决办法:添加启动参数-Dfile.encoding=utf-8 ,则能正常启动并读取远程配置
原文链接:https://blog.csdn.net/qq_43437874/article/details/108625707
20220520 k8s容器日志中文异常
打包好的jarbao,linux服务器上运行正常,日志没有中文乱码
打包为镜像,部署至k8s时,日志输出异常,中文显示为问号
解决办法:
打包镜像时添加如下语句即可解决
ENV LANG C.UTF-8
20220525 quartz调度任务无法执行异常
启动的时候,调度器得名字必须的和之前一样
如果名字不一样,那么之前建好的调度任务将无法执行
20220526 IDEA 命令行异常,系统cmd命令行可以正常执行
换了个电脑,重新装了IDEA,运行mvn命令的时候发现,以前的命令都不能用了
找了很多方法,发现了这种方式
以前的命令
mvn package -Dmaven.test.skip=true
新的命令
mvn package ‘-Dmaven.test.skip=true’
虽然一时解决了,但后续其他的maven命令又不行了
今天突然发现:IDEA命令行的最前面有PS 前缀,
原来是IDEA用了PowerShell 作为命令行执行,整了个大无语
可用以下方式改为cmd
setting->Tools->Treminal->shell path 选择cmd就行了
202200602 fastjson版本更新至1.2.83导致异常
老版本的fastjson出现反序列化bug,涉及项目需要升级版本
但是,升级完之后,调别人接口返回的json数据,不能解析了,会抛出json格式异常
回退老版本就又可以了
感觉像是将返回的json字符串自动转义了一次,toString了一下,再转就ok了
20200602 mysql时间类型数据,自动更新后,少8小时
数据库连接也配置了时区
字段也配置了时间格式
拦截器什么的也都设置了时间格式
但是库里更新的数据,总少8小时。。。
查来查去,发现那个字段是自动根据当前时间戳更新
也就是它的值和mysql本身的时间有关系,和服务的时间没关系
查了下数据库的时间,发现数据库就少八小时。。。。
改改数据库配置就可以了
20220610 ffmpeg命令行执行异常 No such filter
在使用ffmpeg对视频进行多个水印添加和移除操作时,出现了以下情况
##命令如下
添加水印
ffmpeg -i input.mp4 -i img.png -i img2.png -filter_complex “overlay=20:80,overlay=200:80,overlay=150:150” out.mp4
移除水印
ffmpeg -i input.mp4 -vf “delogo=x=1:y=2:w=3:h=4:show=0,delogo=x=1:y=2:w=3:h=4:show=0” out.mp4
上面俩命令
Windows下命令行可以执行,没有异常
linux下命令行执行,也没有异常
但是使用以下Java代码执行命令时,ffmpeg出现了filter发现不了的异常
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
异常排查:
1、怀疑是代码中符合编码问题,代码中输出执行的命令,复制到命令行中,也可以正常执行
2、把双引号换成单引号,也不行,命令行中直接无法执行
3、直接去掉双引号和单引号,命令可以执行了。。。
其他ffmpeg命令均未出现类似的问题,Windows和linux编码均正常,jar包服务编码也正常
且改情况只有服务执行时才会出现,目前服务无法远程调试,待后续排查具体原因
20220615 fastjson序列化异常
维护已有业务时,接口返回参数与定义参数名称不一样
定义为isSuccess,最后结果输出时返回success
使用fastjson后,定义变量不能以is开头,否则会序列化异常
会主动去掉is
可为对应is开头的参数添加get、set方法,可以解决上面出现的问题
后续规范,尽量避免使用is开头定义变量
20220616 windows查找占用端口
netstat -ano |findstr “port”
20220628 ffmepg把视频截图
ffmpeg -i 2.mp4 -s 1280x1024 -vf fps=fps=1/1 %09d.jpg
20220628 IDEA 远程调试
首先启动项目的时候,命令如下
java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=9005,suspend=n -jar /usr/local/big-screen.jar
核心在这里,使用端口为9005
-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=9005
这样配置好之后IDEA中添加remote配置,然后运行,调用部署在服务器上的接口
就可以远程调试了
20220703 GPRC序列化异常
使用阉割版的jdk容器环境,会抛出类找不到的异常
原因是有些jdk环境会缺少jre,导致序列化的时候抛出类找不到的异常
20220703 maven使用技巧
1、为别人提供公共模块的依赖的jar包中,pom中没有packaging这个属性
2、父工程中使用dependencyManagement,子工程中若不引入dependencyManagement的依赖
则不会对项目包大小产生影响
20220703 arthas 服务监控,链路追踪
可以监控java项目的内存使用情况,GC情况
每一个方法的消耗时长等情况
20220704 @Async默认线程数不够,导致业务无法正常执行
@Async异步方法默认使用Spring创建ThreadPoolTaskExecutor。
默认核心线程数:8,最大线程数:Integet.MAX_VALUE,
队列使用LinkedBlockingQueue,
容量是:Integet.MAX_VALUE,
空闲线程保留时间:60s,
线程池拒绝策略:AbortPolicy
@Async默认线程数为8,且线程拒绝策略为等待
@async默认线程数为8,且线程拒绝策略为等待
20220707 @Transactional锁(lock or dead lock)异常
场景 服务A 服务B 为同一个服务,使用同一个数据库
服务A先运行,更新a表,服务B再运行更新a表
此时服务B会抛出异常,表a被锁,服务B的业务无法正常进行,服务A正常
其他使用了事务的方法全部回滚,相应方法不能继续执行
根本原因是mysql在Update带有子查询的时候,子查询的表会锁住,导致该表无法使用
20220707 @Transactional事务传播级别
若某一个类上使用了@Transactional事务注解,那么该类下的所有方法默认全部使用事务
spring 的事务传播级别默认为require,即若使用了事务注解,那么子方法均会使用事务
若该类的某个方法不想使用事务,修改事务传播级别为Propagation.NOT_SUPPORTED(不支持事务)即可
是有七种传播级别
20220707 FastJson转换list时,转换的json出现$ref引用异常
场景,先new俩个ArrayList(),a,b
然后循环a,把a中的实例类添加到b中,再使用fastjson把b转为json
异常就会出现
因为fastjson默认开启引用检测将相同的对象写成引用的形式,引用是通过"$ref"来表示的
上面的场景就是重复引用了,循环引用也会产生这种情况
重复引用的解决方法;
1.单个关闭 JSON.toJSONString(object, SerializerFeature.DisableCircularReferenceDetect);
2.全局配置关闭 JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
循环引用的解决方法:
1.如果你前端用不到这个属性在该属性的get方法上加上注解@JSONField(serialize=false),
2.这样该属性就不会被序列化出来,这个也可以解决重复引用
3.修改表结构,出现循环引用了就是一个很失败的结构了,不然准备迎接StackOverflowError异常
20220715 旧代码if(){} else if(){} 坑
原有业务逻辑大概是这样,猛一看上去,逻辑好像没啥问题,
但仔细看就会发现,他想执行完if里面的东西,若为fals的时候,再去执行else if里的东西,不满足再去执行
else的东西。。。。。直接整麻了
若使用这个逻辑去跑,最终结果是这样的
20220714 redis过期时间设置异常 ERR invalid expire time in setex
该异常为更新redis值时,同时获取到相应key的过期时间,更新时也更新过期时间
但是当过期时间为0或者小于0时就会出现该异常ERR invalid expire time in sete
20220715 docker 容器网络ip分配冲突导致无法调用指定服务器接口
问题如下:
在一次常规的docker服务部署时,之前突然可以调用的接口无法调用了
本地调用也没有任何异常,服务器上却提示网络不可搭,找不到该路由
开始排查,排查过程如下
1、 先与运维沟通,是否有动过网络,沟通后
沟通后后发现该服务器网络与目标口服务器网络没有做任何改动
即不可能是服务器之间的网络问题
2、然后开始排查docker容器的网络分配,突然发现有一个容器的ip是 192.168.0.1
然而服务需要调用的接口地址为 192.168.0.32
而在调用接口的时候,先去查了docker的服务路由,然后走服务器的路由
这就导致容器里的服务先找到了docker的路由,没有去走服务器的路由
然后就无法调用接口了。。。
解决
查看索引容器分配的ip
docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)
查看某一个容器的具体分配信息
docker inspect 容器id
关闭对应docker容器
相应docker的yml文件中加入如下内容,重启即可解决
version: '2'
services:
java-server:
image: java-server
ports:
- '10000:10000'
restart: always
volumes:
- ./config:/usr/local/config
container_name: java-server
privileged: true
networks:
- java-server
networks:
java-server:
driver: bridge
20220801 spring事务传播导致业务逻辑无法执行
方法A中使用了事务,去做数据库删除操作
方法B需要查询方法A删除的数据,然后做后续操作
方法A执行完删除后调用方法B,事务未提交,方法B也在事务中
查询不到删除的数据,导致了方法B的业务逻辑出现问题
此处需要修改事务传播级别,方法B中不使用事务
1、propagation-requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,则加入到这个事务中,这个是默认选项。
2、propagation-supports:如果当前有事务,则支持当前事务,如果当前没有事务,就以非事务方法执行。
3、propagation-mandatory:如果当前有事务,则使用当前的事务,如果没有当前事务,就抛出异常。
4、propagation-required_new:无论当前有没有事务,都要新建事务,如果当前存在事务,把当前事务挂起。
5、propagation-not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6、propagation-never:以非事务方式执行操作,如果当前事务存在则抛出异常。
7、propagation-nested:如果当前存在事务,则作为子事务在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
20220802 float类型取整异常
如下代码-0.5f向上取整是-0.0,不是0
向下取整,为-1.0
public static void main(String[] args) {
float d = -0.5f;
System.out.println(Math.ceil(d));
System.out.println(Math.floor(d));
}
20220802 使用Java代码在windows10中调用exe可执行文件异常
场景如下
cmd命令行执行exe文件时,exe文件可正常执行
将相同语句使用Java代码执行时,会抛出exe需要文件无法找到的异常
原因
是因为使用java执行cmd命令时,执行命令的目录会默认为当前java程序执行目录
而不是exe文件所在目录
可以理解为在当前程序目录下面,执行了exe,导致exe找不到需要的文件
这就需要执行cmd命令的时候,指定cmd命令在哪里执行
参考代码如下
/**
* @param exePath exe文件路径
* @param sampleFilePath exe文件所在目录
*/
private void excuteExe(String exePath,String sampleFilePath) {
try {
//调用exe
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("cmd /c " + exePath + "", null, new File(sampleFilePath));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
//读取执行结果
String line;
while ((line = bufferedReader.readLine()) != null) {
log.info("----开始执行exe;line={}", line);
}
}catch (Exception e){
}
}
20220803 字符串操作技巧
String,StringBuffer,StringBuilder 进行大量字符串修改时
StringBuffer,StringBuilder要优于String
50w的字符串拼接操作,String需要1分30s
StringBuffer,StringBuilder只需要几十毫秒
原因就是每次对String字符串就行修改时,都是新建一个字符串,50w拼接
相当于new了50w次(不是很准确,大概就是这个意思,因为不一定new50w次,字符串也有缓存)
20220804 阿里云oss java sdk下载文件异常,提示NoSuchBucket
bucketName为test
文件目录为tmp/20220804/test.zip
下载文件时,抛出异常NoSuchBucket,tmp
但在请求oss时,设置的bucketName为test,也就是说在发生请求时
阿里云oss提供的sdk把tmp当做了bucketName
目前使用的是sdk版本是2.2.3
更新版本为3.15.0后问题修复
20220191 logback配置不生效-覆盖问题排查 耗时3天
1、问题描述
项目提供了统一的logback日志配置模块,其他项目输出日志时都需要依赖该模块
但目前有这样一个现象,有多个子项目归属同一个父项目,父项目依赖了改日志配置模块
但是子项目在运行时,有些子项目输出的日志符合依赖的日志模块,有些子项目输出的日志模块不符合
2、问题排查
1:检查日志不生效的子模块,是否存在依其他模块依赖logback,导致覆盖了独立日志模块的配置
排查后,没有发现logback.xml相关的配置
2:是否没有读取到独立日志模块的配置文件,使用配置文件配置logback路径后,依然不生效
3:尝试网上提供的解决方法,均无法解决,重新整理思路,观察日志问题
此时发现一个现象,在IDEA中,项目启动的前半程时,日志中的INFO,ERROR在控制台是没有颜色的
在后半程时,输出的日志突然开始有了颜色,并开始有颜色的上一行日志中,抛出了如下异常
No context given for c.q.l.core.rolling.SizeAndTimeBasedRollingPolicy
但是在独立的日志模块中,该配置是配置了的,就不应该抛出该异常
抛出了,即说明没有去走项目中的配置,走了其他地方的配置
且其他地方的配置级别,要远远高于自定义的配置
给人的感觉像是项目启动后,才去加载的日志配置
3、问题解决
顺着上面2.3中的思路,先去找出spring boot加载日志模块的代码,
参考了下面这篇博客
https://blog.csdn.net/weixin_44646065/article/details/125314449
通过这个博客,在源码中找到了加载日志模块的方法,然后开始debug
在一步步的debug中,突然发现在走完spring boot的log加载后
走到了一个自定义logback配置类中
该类中用@PostConstruct注解,在项目启动后,使用类的方式,初始化了logback的配置
即没有走logback.xml配置,而是通过java类的方式,去初始化logback配置
至此,问题已经定位到,去除改自定义配置类后,日志输出正常
20221008 feign请求返回值反序列异常-LocalDateTime类型无法转换导致
1、问题描述
在开发Feign接口时,结果返回的最后一步时,rpc接口的提供方突然抛出一个异常
无法将定义好的包装类转化,即序列化异常,其他feing接口均正常
2、问题排查
1:先排除rpc接口的实现业务逻辑,检查是包装类型依赖是否引入错误
检查后没有
2:再排除业务逻辑,检查是否有数据返回,检查后数据均正常
3:检查包装类型中的变量,此时看到了LocalDateTime类型
但此时没有发现是该原因
3、尝试解决
1:此时自定义的包装类型不行,那么之间返回Object是否可以?
之间返回了Object,异常消失了,可以正常调用
但是接收起来需要在调用方进行json对象解析,还是比较麻烦
2:那为什么自定义包装类型可以,自定义的类型不行
返回结果的时候一步步的debug,发现当自定义变量类型LocalDateTime时
会抛出该异常,也就是当前无法序列化LocalDateTime,导致了异常发生
有俩种方法,都需要引入下面的依赖
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
//一种是在LocalDateTime类型的变量上面使用注解指定序列化方式
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
//一种是重写ObjectMapper
当新项目时,推荐使用ObjectMapper
老项目时,还是使用注解比较好,比较序列化的改变可能会导致其他不受控因素发生
20221101 this事务或异步失效解决办法
1:自己依赖自己
即在service类里使用自己
2:在自身方法里使用代理获取到自己的对象
然后使用异步或事务方法
3:失效原因好像是事务或异步都是通过代理实现,之间使用this是使用的自己当前的对象,没有使用
代理获取到对象,也就失效了,大概是这个意思,详细的原因可以自行查询。
@Service
public class TestService{
@Autowired
private ApplicationContext context;
@Autowired
@Lazy
private TestService testService;
public void testFunction(){
//方法1
testService.testAsync();
//方法2
TestService proxySelf = context.getBean(TestService.class);
proxySelf.testAsync();
}
@Async
public void testAsync(){
//todo 业务逻辑
}
}
20221114 Feign内部服务接口调用时请求头问题
1、问题场景:
场景如下:前端通过浏览器或APP调用服务A接口,服务A内部Feign调用服务B接口
此时服务A可正常使用请求头参数,服务B也需要使用这些请求头参数,
获取时无法获取
2、问题排查与解决:
代码无异常抛出,只是获取不到对应请求头的值,那么在服务B中进行日志打印,打印请求头
发现没有该值,服务A中是有该值的,那么请求头默认是不会传递的吗?
后经查询后发现,默认配置下,请求头的确不会传递,若在Feign调用过程中进行请求头的传递
有俩种方法:
1:增加feign配置,可以传递请求头;
2:在最外层捕捉到需要用的请求头,将其添加为feign接口参数
推荐使用第二种,避免请求头传递带来的安全风险
20221114 spring boot打包部署后,无法正常获取resource中的静态文件
1、问题场景:
在开发excel模板下载功能时,需要将指定模板返回给前端,不能动态生成,
便将其放入resource目录下,在本地测试时没有问题,但部署在容器中后,便无法正常获取文件,
提示获取文件异常
2、问题排查:
第一次遇到该问题,在本地环境中、Linux服务器中部署服务均未遇到该问题,但是在容器化部署时,遇到了该问题
经查询后发现是资源文件获取的方式有问题
刚开始使用的获取方式如下
ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + filename).toString();
修改为如下方式即可正常获取
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(“template/filename”);
3、问题原因:
没打包之前,文件是真实存在与文件系统中的,
一旦打成jar包后,使用File是访问不到资源的内容的,推荐使用getInputStream()的方法
20221207 feign内部Get接口请求参数过长导致400异常
1、问题场景
业务正常的feign接口调用,突然抛出400异常,且对应服务上下游业务都没有抛出异常
且只对某条数据出现400,其他数据均正常
2、问题排查
1、怀疑参数没有判空导致,于是加了判空逻辑和日志,打印请求参数
发现请求参数并不为空,只是很多,那么就是定义的内部接口有问题
2、看到定义的feign接口请求类型为GET,复制出请求参数后,发现请求参数过长
接口请求改为post,参数接收使用请求体接收后,该问题消失
3、问题原因:
feign内部调用其实也是转为http调用,自然会存在http接口调用类似的问题;
此处就是get请求中,url最大长度超出限制,导致了无法正常传入参数,接收方没有接到参数
抛出400,参数没有传递的异常
20221207 由于业务采用纯数值id过长,导致解析为Long类型是超出Long类型最大值
用户分为两部分,A,B
俩用户分表存,一个唯一主键为Long类型
一个唯一主键为字符串类型,且长度很长,在业务逻辑中,俩种主键对应的业务含义一样,
均为用户唯一标志
在一张业务主表中,用户标志字段会存在A、B俩种id值
这就导致查询去A模块查询A用户信息时,出现Long解析异常,因为B的长度太长了
此处应根据业务主表的类型,去分类用户id查询,避免出现该异常
20230105 通过网关调用服务接口,接口间歇性异常返回500
1、问题场景
通过网关调用某模块接口时,接口偶现500异常,connection time out ,
2、问题排查
1、网关与服务模块为容器化部署,怀疑可能容器内网络有问题,排查后网络正常;
2、查看调用服务模块日志,服务正常,且没有异常日志输出;
3、查看网关模块,网关输出日志如下:显示服务网络不可达;排查网关后发现网关nacos配置
可能有问题,修改部署后,问题依然存在;
4、nacos排查,查看相应模块服务有没有注册到nacos,注册状态也正常;
于是在发生异常时,查看nacos服务状态,nacos服务健康状态为false,即服务不健康
但是查看相应服务模块,服务模块运行正常,且在几分钟后,nacos健康状态自动恢复;
将nacos中对应服务下线后,发现又有服务注册上来,但是这个服务只启动了一个,
删除该服务,重新注册后,问题修复。
3、问题原因:
原因就是nacos中注册的服务与实际服务不符,具体原因不明,猜测可能为nacos缓存问题,
下线的服务没有全部删除,导致新注册的服务ip被覆盖,忽隐忽现可能为nacos服务发现机制与缓存
相互覆盖导致。
20230113 restTemplate调用接口数据返回缺少异常
1、问题场景
业务代码中,通过restTemplate.getForEntity(url,Map.class)调用接口时,出现了以下情况;
返回的json对象的list中,全部只有一条数据,但是服务提供方响应数据的时候确认了每个list中
都有多条数据。
2、问题排查
1、刚开始怀疑服务提供方数据返回异常,于是查看服务提供方的接口响应日志,发现并没有问题;
每个list中数据量均正常;
2、在服务调用方打印响应结果,发现打印出的结果中,list数据已经减少,那么问题即出现在服务调用方;
定位到问题出现位置,开始排查为什么缺少,debug时发现解析响应数据时,出现了数据丢失的问题;
3、问题原因
查了一些资料,大概是如下的问题:
举个个例子:是map中嵌入list,Map<String,Object>中Object一旦映射的是List,自动映射的返回数据只会返回List的最后一条数据,
原因是map.put()的键相同,导致覆盖。进而导致数据缺失。
使用java自动映射的对象类型:Map.class List.class Object.class等,必须保证接口返回的数据类型是单一的某一种,
(无论数量多少,只要种量为一即可),而不能是多种数据类型嵌套的复杂数据。一旦为复杂数据只能手动创建对应实体类。
总的来说就是远程接口返回的数据类型是使用了泛型,或者返回数据所使用的实体类中数据类型不唯一,
那么restTemplate接收的时候也只能使用对应实体类,而不能让java自己去映射。
4、解决方案,目前有如下俩种:
1、配置restTemplate序列化配置,具体方案可以自行查询;
2、通过restTemplate的exchange方法来解决:可以参考如下代码:
public void queryTest(String name) {
//CommonResponse和CustomDTO为自定义响应类
ParameterizedTypeReference<CommonResponse<CustomDTO>> typeRef = new ParameterizedTypeReference<CommonResponse<CustomDTO>>() {};
//设置Http的Header
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
//设置访问参数
HashMap<String, Object> params = new HashMap<>();
params.put("name", name);
//设置访问的Entity
HttpEntity entity = new HttpEntity<>(params, headers);
CommonResponse<CustomDTO> response = restTemplate.exchange("url" , HttpMethod.GET,entity,typeRef).getBody();
log.info("queryOrderHeaderTest响应json,[{}]",JSONObject.toJSONString(response));
return response.getData();
}
5、参考链接:
https://www.bbsmax.com/A/1O5EY7PW57/
https://www.cnblogs.com/yzyBalance/p/13546552.html
https://blog.csdn.net/qq_37855749/article/details/117691268
20230129 xxljob日志抛出中文异常导致任务无法停止,一直重试
xxljob执行的时候抛出的异常日志包含中文字段
重新拉取解析重试的时候 无法解析成json
所以就一直出错 一直重试
在这里插入图片描述
20230207 skywalking agent引入后,项目启动时Controller初始化异常
1、问题描述
- 项目引入skywalking agent后,部署服务时启动失败,抛如下异常
- 本地引入skywalking agent后,项目可正常启动
- skywalking agent版本为8.9.0
1.1 异常日志核心内容为实例化bean失败,缺少需要空参构造,但在本地引入agent后没有出现该异常
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1270)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1164)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
1.2 controller代码如下,此处采用了构造注入的方式实例化Service
2、问题排查
2.1 skywalking-agent版本与插件检查
- 本地的skywalkingagent无异常,docker镜像中使用的skywalking-agent会出现该异常,俩个agent版本均一致,唯一不同点在于镜像中的agent移除了不用的插件,添加了部分插件,与本地agent插件不同,怀疑可能是镜像中添加的插件影响导致,开始对比插件;
- 对比移除相应添加插件后,问题依旧无法解决,直接把本地agent中的全部插件复制到镜像中后,服务可正常启动,那么就不是添加插件导致的问题,而是缺少插件导致的问题;
- 由于插件过多,有八九十个,无法明确的找到缺少什么插件,于是去skywalking的github上看下是否有人遇到过相同的问题,进查询后崅实有类似的问题,虽然原因各不相同,但核心内容均为实例化类失败,猜测可能为缺少spring插件导致;
- 搜索本地agent的spring相关插件,根据插件名找出相关性较高的插件,猜测可能为如下几个插件
- 一个个引入,然后启动验证,最终定位到了是缺少了apm-spring-core-patch-8.9.0这个插件
3、问题原因
- 在上面的controller代码中,使用了构造注入的方式实例初始化,这就导致了初始该类时需要空参构造,然而代码只提供了有参构造,实例化找不到构造函数,就抛出了异常;
- 此时也可以通过增加空参注解去解决,但是涉及到很多代码的改动,故抛弃;
- 那么为什么引入了apm-spring-core-patch-8.9.0这个插件就可以正常运行启动呢?把这个包解压后,看下代码做了什么事情,发现了如下一段代码,在这段代码中,进行了实例化增强,对所有有构造函数的类先进行了初始化,并存入缓存,这样在spring实例化该类时,先在缓存中查到了该类,然后直接取出,就不会抛出实例化失败的异常了:
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
public class AutowiredAnnotationProcessorInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
public AutowiredAnnotationProcessorInterceptor() {
}
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
}
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
Class<?> beanClass = (Class)allArguments[0];
if (!EnhancedInstance.class.isAssignableFrom(beanClass)) {
return ret;
} else {
Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = (Map)objInst.getSkyWalkingDynamicField();
Constructor<?>[] candidateConstructors = (Constructor[])candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
Constructor<?>[] returnCandidateConstructors = (Constructor[])((Constructor[])ret);
if (returnCandidateConstructors != null) {
candidateConstructors = returnCandidateConstructors;
} else {
Constructor<?>[] rawConstructor = beanClass.getDeclaredConstructors();
List<Constructor<?>> candidateRawConstructors = new ArrayList();
Constructor[] var12 = rawConstructor;
int var13 = rawConstructor.length;
for(int var14 = 0; var14 < var13; ++var14) {
Constructor<?> constructor = var12[var14];
if (!Modifier.isPrivate(constructor.getModifiers())) {
candidateRawConstructors.add(constructor);
}
}
if (candidateRawConstructors.size() == 1 && ((Constructor)candidateRawConstructors.get(0)).getParameterTypes().length > 0) {
candidateConstructors = new Constructor[]{(Constructor)candidateRawConstructors.get(0)};
} else {
candidateConstructors = new Constructor[0];
}
}
candidateConstructorsCache.put(beanClass, candidateConstructors);
}
return candidateConstructors.length > 0 ? candidateConstructors : null;
}
}
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
}
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap(20);
objInst.setSkyWalkingDynamicField(candidateConstructorsCache);
}
}
20230214 @Aspect日志拦截器无法拦截api请求异常
1、问题场景:
在排查一次线上问题时,突然发现异常的接口(a)没有输出请求与响应日志,但是其他接口(b)请求响应日志正常输出,
且这俩个接口在同一个controller中
2、问题排查
1、a、b两接口在同一个controller中,那么先检查@Aspect日志拦截器,看是否做了特殊处理,
排查后发现没有特殊处理;
2、对比两个接口,使用的注解、路径、请求参数等信息,均无异常;
在反复对比的过程中,发现a接口没有修饰符,而b接口有public修饰符;
a接口加上public修饰符后,日志拦截器正常工作;
3、问题原因
1、没有加修饰符时,api提供类中的方法的作用域为default,其他包无法访问;
也就导致了日志拦截类没有访问到该api,定义为public时,就可以拦截到了。
息空指针异常
1、问题场景:
正常业务中使用RequestContextHolder.getRequestAttributes()时可以获取到请求头中的一些用户信息,
在一次接口优化时,需要优化响应时间,目前网关设置响应时间默认为2分钟,但涉及要处理的数据量大时,
2分钟不够了,且直接返回了超时异常(实际业务正在处理中),导致用户体验很差,
于是将部分耗时业务使用异步的方式去处理(该业务为实际处理数据),先返回结果,提示处理中;
但是异步线程中使用了RequestContextHolder.getRequestAttributes()获取时无法获取用户信息,就抛出了空指针异常
2、问题排查:
1、空指针异常较好排查,直接把报空的对象打印一下,发现通过RequestContextHolder.getRequestAttributes()获取的对象就为空;
但是不是用异步注解时,程序无异常
3、问题原因
1、问题原因比较明显,使用异步注解时,会开启一个新线程去执行业务,新线程中没有传递Request相关的信息;
那么在新线程中肯定无法获取到相应的值使用如下方法可以解决:
1:将要获取的对象作为值传递到异步方法与业务中,但不会从根本上解决问题;
2:在使用异步方法前的业务加上如下代码:
RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);
通过该方法可以将主线程的上下文数据共享给子线程
RequestContextHolder内部也是使用了俩个ThreadLocal去存储数据
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<>("Request attributes");
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
new NamedInheritableThreadLocal<>("Request context");
NamedInheritableThreadLocal为可继承线程,子线程会继承改线程中的内容,当setRequestAttributes设置为true时
子线程就可以使用父线程中的RequestAttribute信息了。
20230407 记一次接口速度调优过程
1、问题场景:
有一个历史综合信息查询接口,响应速度很慢,已经到了快10s才会响应,导致前端界面加载过慢,必须得优化。
2、问题排查与解决:
列表查询的业务比较明确,即查询一个主体的不同的附属信息,需要查询mongo、mysql以及rpc远程接口调用,才能获取到全部信息;
分析业务代码后,发现在查询到基础数据后,会进行for循环调用查询mongo、mysql、以及调用远程rpc接口,这都有可能降低响应速度;
排查后大概以下业务可能会导致响应慢:
1、循环调用rpc接口查询了主体日志信息,且该rpc接口中查询了mysql,然后累加获取到mysql数据;
2、循环查询mongo,且使用了类似sql查询,limit1的操作
针对以上问题进行优化:
1、rpc接口改为一次查询多条数据,并在获取结果时使用sql对数据进行聚合统计;此处修改后,响应速度平均在4s左右
降了一大半;
2、循环查询mongo,且使用了类似sql查询,limit1的操作,此处改为使用mongo聚合查询,类似sql中的group by+sum
此处修改后,速度优化了300ms左右,接口响应速度平均大概在3.7s左右
目前根据业务分析不出来哪里还可能需要优化了,开始上科技:arthas
```trace -E class_path method|method2|.... ```
1、先直接用arthas的trace命令追了接口,发现追踪到的一些方法耗时都很短,基本就是几毫秒,不会影响速度;
那么就是有方法没有追到;
2、仔细排查业务代码,发现如果类的set方法中的入参是一个方法,那么这个方法就不会被追踪到,这些比较隐蔽;
花了点时间一个个都找了出来,然后再用trace进行追踪,慢的方法一目了然。
3、也是在for循环的时候进行查询了mongo,查出每一个主体信息在该mongo中的全部数据,然后根据查出来的数据进行分类统计;
这样如果某一个主体在mongo中有大量数据时,就会非常耗时,数据量小的主体,响应速度就很快;