maven是java开发常用的工具,可以很快地对项目进行构建,包含了clean、compile、package和install等功能。在平时使用中,如果在maven引入依赖不对时,就很容易造成打包不成功,有时解决打包的问题就可能要很久。所以,在平时一定要多总结项目常见的问题,避免因maven打包问题影响了开发进度。
下面就总结一下目前maven常见的问题。
Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.1:test (default-test)
报错的原因就是test类打包的问题,直接去除掉test即可,下面两种方式都可以。
- 在用到的测试类test中都添加上@Ignore
- 直接在pom文件中去除test打包的内容即可。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
项目的包中有某个类,却一直引入不了
有时将某块代码复制到某个类中,一个类名明明就存在,却始终引入不了。那么解决办法有如下几种:
- 重新写一下需要用的类名:有时是因为直接复制粘贴无法正常引入,需要重新写一下。
- 清除缓存:由于缓存的原因,不能正常加载。那么在idea左上角File-Setting-Invalidate Caches / Restart -Invalidate
引入的依赖冲突导致没有引入高版本jar,而是引入到低版本的jar
分两种情况:
- 在引入依赖时时用到了两个不同版本的jar
生产发布时报错:
java.lang.NoClassDefFoundError: org/apache/httpclients
在pom文件中要引入的是:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
但是查看打的jar包,引入的httpclient依赖版本竟然是4.0.1的版本。
但是在pom文件中已经指定了4.5.6的版本了,为什么会引入4.0.1的版本呢?
经过排查,发现在工具类用httpclient时使用的架构提供的框架的jar包,而其中引入的jar就是4.0.1。
所以,将使用到4.0.1的pom和代码中的依赖直接调整为高版本的版本就可以了。
- 低版本的依赖直接继承了parent的标签的内容,而parent中依赖低版本的jar
在启动时,一直报找不到nacos为2.1.3的
经排查发现,项目中有多个module,
在最终打包的pom文件中,架构提供的framework-common中引用的nacos为2.1.3,
但是在依赖其他模板时:用到的nacos并没有指定版本号。
如果在pom中需要的jar没有引用指定版本号时,就会用parent的版本。
而这个parent使用的架构提供的框架使用的nacos版本号是2.1.2。所以启动时就直接只加载了2.1.2,而没有加载到2.1.3。
解决办法:
在依赖的模块直接指定nacos的版本,而不要用默认的parent。或者升级框架版本。
no main manifest attribute, in xxx-xxx-xxx.jar
在linux打包时报这个错误。需要在pom文件设置打包:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.3.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile
报错信息:
Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project springbootdemo: Fatal error compiling: 无效的标记: -parameters
错误的原因:
由于项目中所需jdk版本和你当前使用的jdk版本不一致导致的,因为我项目的pom.xml中定义了java版本为1.8,但是我实际idea中run这个项目却是1.7
<java.version>1.8</java.version>
解决办法:
更换当前jdk版本为项目所需jdk版本即可
要是你在intellij idea里面的maven窗口点击的打包编译的话,就在intellij idea设置项目jdk版本,直接Ctrl+Alt+s进入设置界面进行设置
指定/调整打的jar包名称:
在pom.xml文件中标签中添加finalName即可:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.3.RELEASE</version>
</plugin>
</plugins>
<finalName>springboot-station-demo</finalName>
</build>
打包时找不到符合的符号
这种原因也是有缓存jar包的缘故。解决的办法:maven-clean-install
如果还不行,右键整个项目-Maven-Reimport
如果还不行,就在File-Project Structure-Project Settings-Modules中选择清除掉当前报错的包。然后整个项目-Maven-Reimport
在idea中配置好了maven仓库,却一直下载jar到系统默认的路径
需要在maven的jar包的setting.xml中设置指定的路径才行
<localRepository>/usr/local/java/repository</localRepository>
pom文件中project显示setting.xml有error错误
pom文件一直有error报错,就花了很多精力去调整,但是最后还是找不到原因。
最终发现还是直接找一个别人正确的setting.xml文件直接替换最快。
还是不要把太多的时间用在配置这个上面。
idea中下载了maven中的jar包依赖,但仍然还是有红色波浪线
idea中下载了maven中的jar包依赖,但是在libraries或者在右上角的Maven Project的Dependencies/Plugins仍然还是有红色波浪线。
可能是上一步中修改了仓库地址,没有将有些依赖下载完整,那么可以点击Maven中的下载按钮即可。
SLF4J: Class path contains multiple SLF4J bindings.
启动时显示日志相关的jar有重复:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/Software/Repository-Station/org/apache/logging/log4j/log4j-slf4j-impl/2.11.2/log4j-slf4j-impl-2.11.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/Software/Repository-Station/org/slf4j/slf4j-log4j12/1.7.25/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
排查发现有多个依赖都有日志的依赖,那么把不需要的日志依赖排除掉即可。
<exclusion>
<artifactId>spring-boot-starter-log4j2</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
项目中兼容同一名称的不同版本的jar内容
redis单点和哨兵并行
在做项目更新优化时,老项目要将redis单点改为redis哨兵和单点并行的模式。
redis单点用的版本是2.1.0。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.1.0</version>
</dependency>
但2.1.0的redis没有哨兵模式,无法正常引用,而2.9.0的有哨兵模式。而这个2.1.0版本引用的地方特别多,不可能为了改哨兵强制升级jar版本,这样太费时间又风险太大了。
那么可以用jarjar.jar来兼容版本。jarjar可以将redis-client 2.9.0修改成你想要的名字,比如myredis-client,那么调整后整个包名都是修改后的名称,这样就能正常使用2.9.0了。
<dependency>
<groupId>myredis.clients</groupId>
<artifactId>myjedis</artifactId>
<version>1.0</version>
</dependency>
jarjar具体的依赖:
<!-- https://mvnrepository.com/artifact/com.googlecode.jarjar/jarjar -->
<dependency>
<groupId>com.googlecode.jarjar</groupId>
<artifactId>jarjar</artifactId>
<version>1.3</version>
</dependency>
具体操作如下:
- 将如下内容放到任意一个盘下的同一个文件夹中:
jarjar.jar
redis-client-2.9.0.jar
新建rule.txt - 在rule.txt文章中输入以下内容:
## 内容格式 rule 要改变的包名称 改变的名称
rule redis.clients.jedis.** redis.clients.myjedis.@1
- 在cmd中输入:
#java -jar 你的jarjar.jar的名称 process rule.txt 要改变的jar包名称 最终的jar名称
java -jar jarjar-1.3.jar process rule.txt redis-client-2.9.0.jar myredis.clients.jar
看到jar名称改变成功,大功告成!
那么在代码中需要引用2.9.0的,就需要将redis的完整包名地址写上,比如:
redis.clients.myjedis.c.Jedis jedis=null;
另外为了方便别人正常查看和打包,需要将这个jar上传到私服上。
redis哨兵和cacheCloud并行
项目中需要用到redis的分布式锁,而不同的地方redis有用到哨兵和集群模式。那么哨兵和cacheCloud引用的依赖:
redis哨兵用的依赖是:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
cacheCloud引用的依赖是:
<dependency>
<groupId>com.sohu.tv</groupId>
<artifactId>cachecloud-open-client-redis</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
在代码中写了JedisCluster调用set方法时却一直报错:
具体代码:
@Autowired
private JedisCluster jedisCluster;
public void tryLock(String key,int seconds){
String isExists=jedisCluster.set(key,value,"NX","EX",seconds);
}
报错信息:
Cannot resolver method set() ...
查看JedisCluster时发现,引用的cacheCloud的方法,cacheCloud的依赖并没有这个set方法,而redis-2.9.0的依赖有这个方法。但是在引用时一直引用到cacheCloud的依赖,即使在引用处加上redis.client.jedis.JedisCluster的前缀也引用不了redis.client-2.9.0。
查看源码发现,redis.client-2.9.0还是cacheCloud,引用的都是redis.client.jedis.JedisCluster,名字竟然还一模一样。
原来cacheCloud的依赖底层并没有修改redis的依赖名称,而是重写了里面的方法,就导致引用时出错。真是坑啊!
那么如何解决呢?
将pom文件中redis-2.9.0的依赖放在cacheCloud的前面,那么在加载时就可以优先加载redis-2.9.0了。
Failed to configure a DataSource: ‘url’ attribute is not specified and no embedded datasource could be configured.
项目启动时报错:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
启动类需要禁止springboot自动注入数据源配置:
@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class})
java.lang.NoClassDefFoundError: org/springframework/boot/bind/RelaxedPropertyResolver‘
引入alibaba druid时报错:
java.lang.NoClassDefFoundError: org/springframework/boot/bind/RelaxedPropertyResolver
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getExcludeAutoConfigurationsProperty(AutoConfigurationImportSelector.java:215) ~[spring-boot-autoconfigure-1.5.12.RELEASE.jar:1.5.12.RELEASE]
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getExclusions(AutoConfigurationImportSelector.java:209) ~[spring-boot-autoconfigure-1.5.12.RELEASE.jar:1.5.12.RELEASE]
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.selectImports(AutoConfigurationImportSelector.java:99) ~[spring-boot-autoconfigure-1.5.12.RELEASE.jar:1.5.12.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser$DefaultDeferredImportSelectorGroup.process(ConfigurationClassParser.java:892) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGrouping.getImports(ConfigurationClassParser.java:878) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:804) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:774) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:185) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:315) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:232) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:705) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:531) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
根据报错的信息可以得知:
org.springframework.boot.autoconfigure出现了两个版本,分别是1.5.12和2.1.3。那么在pom文件中搜索到autoconfigure依赖发现两个地方的依赖不一致:
那么就需要将druid-spring-boot-starter的spring-boot-autoconfigure排除掉。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.1</version>
<exclusions>
<exclusion>
<artifactId>spring-boot-autoconfigure</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
Class path contains multiple SLF4J bindings.
项目启动后,报错日志依赖重复:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/Software/Repository-JobsTribe/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/Software/Repository-JobsTribe/org/apache/logging/log4j/log4j-slf4j-impl/2.11.2/log4j-slf4j-impl-2.11.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
那么需要排除多余的日志依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.3.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>