SpringBoot解決jar包沖突
今天SpringBoot項(xiàng)目打包發(fā)現(xiàn)一直在報(bào)錯(cuò)
包jar包沖突,找了好久才找到結(jié)果,期間遇到一片博客很討人厭,我這里想評(píng)論一下他(原因:我沒有博客園不能直接評(píng)論,所以這里寫一篇博客記錄一下,并提供正確的解決方案)
上圖:
說一下:首先,你給的方法很泛(不是煩沒打錯(cuò)字)只是市面上大多數(shù)可以解決的套路,
再者,你給的解決方案并沒有真正的解決問題。所以我留下一句話:不喜勿噴。
SpringBoot事實(shí)上是很好的,jar包沖突的時(shí)候,它是有提醒你了的,啟動(dòng)第一行就說了有多個(gè)類路徑j(luò)ar包存在:Class path contains multiple SLF4J bindings.
SpringBoot適合于小團(tuán)隊(duì)及個(gè)人開發(fā)。是比較方便的。
為什么我要寫這篇博客呢,因?yàn)槲铱吹絡(luò)ar沖突的真正原因后,很生氣,因?yàn)樵虿⒉灰欢ㄔ赟pringBoot 我這里查出的是騰訊云的cos-api也引入的了日志jar,所以導(dǎo)致沖突,這里是SpringBoot引入cos-api,你就說SpringBoot,如果SpringBoot是被被人引入的,你是不是也要說其他的工具不好呢???再者不好你為什么要用,要記錄???這只不過是想比較而言,技術(shù)沒有老舊,沒有好壞,只有喜歡,不喜歡,很多時(shí)候有些公司用的還是一二十年前的技術(shù),可能是有些原因不能更換,但是我相信,它能存在在這個(gè)世上并風(fēng)靡一時(shí),說明它一定有它的獨(dú)特之處。
接下來就是,
我查到的一個(gè)解決方案,可使用所有jar包沖突問題
以eclipse為例:
這樣的開發(fā)工具都會(huì)有一個(gè)功能:就是查詢jar包直接引入/jar包間接引入的功能
如果你不知道你使用的工具怎么找到這個(gè)查找頁面:百度搜索:eclipse 看引入jar 包的聯(lián)系(idea同理)
說實(shí)話idea的更清晰一些,它是圖形化界面
找到?jīng)_突的jar包,去除沖突的包即可
代碼如下:
<dependency> <groupId>com.qcloud</groupId> <artifactId>cos_api</artifactId> <version>5.5.3</version> <exclusions> <!-- <exclusion> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </exclusion> --> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency>
聲明:我只是對(duì)SpirngBoot報(bào)不平,沒有對(duì)任何人做人身攻擊。不喜勿噴
spring boot jar沖突問題集錦
總結(jié)下spring boot項(xiàng)目搭建過程中,沖突解決的一些小經(jīng)驗(yàn)
1、日志jar包沖突
1.1、日志主要是spring boot自帶spring-boot-starter-logging的排除
一是要用log4j2,二是xdcs不排除這個(gè)也會(huì)有沖突。(隱秘程度:低;重要程度:高)
<exclusion> <artifactId>spring-boot-starter-logging</artifactId> <groupId>org.springframework.boot</groupId> </exclusion>
1.2、引的日志jar頗多
可能會(huì)有別的jar里也帶了沖突的class,但是不影響啟動(dòng),屬于可排可不排。可能會(huì)導(dǎo)致測試環(huán)境起不來。(隱秘程度:低;重要程度:高)
//這是舉個(gè)例子 <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/Users/xmly/.m2/repository/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:/Users/xmly/.m2/repository/org/slf4j/slf4j-log4j12/1.7.5/slf4j-log4j12-1.7.5.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] //這是啟動(dòng)時(shí)對(duì)應(yīng)的報(bào)錯(cuò),經(jīng)檢驗(yàn),這個(gè)不影響啟動(dòng)
2、本地ok,測試環(huán)境失敗之mainstay
發(fā)測試時(shí),出現(xiàn)過mainstay的yml解析失敗的問題,maven helper排jar包并未顯示有沖突,tree搜索mainstay,發(fā)現(xiàn)了一些貓膩。passport-sso-api(0.0.14-M3,下面用到的也是這個(gè)版本)這個(gè)jar包里包含了這個(gè)mainstay的jar,最終導(dǎo)致了解析失敗。后續(xù)登錄驗(yàn)證可以接下網(wǎng)關(guān)鑒權(quán)等方式,這個(gè)jar沖突應(yīng)該就不會(huì)出現(xiàn)了。(隱秘程度:高;重要程度:中)
<exclusion> <artifactId>mainstay-rpc-thrift</artifactId> <groupId>com.ximalaya.mainstay</groupId> </exclusion>
3、本地ok,測試環(huán)境失敗之servlet
發(fā)測試時(shí),出現(xiàn)過servlet2和spring boot內(nèi)置tomcat class重名沖突的問題,一般主要passport-sso-api和xdcs默認(rèn)會(huì)帶這個(gè),排掉即可(隱秘程度:中;重要程度:高)
<exclusion> <artifactId>servlet-api</artifactId> <groupId>javax.servlet</groupId> </exclusion>
4、本地ok,測試環(huán)境失敗之tomcat
發(fā)測試時(shí),也出現(xiàn)過passport-sso-api這個(gè)jar包里包含的spring-instrument-tomcat和spring boot內(nèi)置tomcat沖突,排掉即可。后續(xù)登錄驗(yàn)證可以接下網(wǎng)關(guān)鑒權(quán)等方式,這個(gè)jar沖突應(yīng)該就不會(huì)出現(xiàn)了。(隱秘程度:高;重要程度:中)
<exclusion> <artifactId>spring-instrument-tomcat</artifactId> <groupId>org.springframework</groupId> </exclusion>
5、本地ok,測試環(huán)境失敗之spring asm
測試環(huán)境出現(xiàn)過passport-sso-api里spring asm與spring-boot-test-start沖突的情況,排掉排掉。passport-sso-api這個(gè)jar包含的jar比較多,后面建議用注解或者網(wǎng)關(guān)鑒權(quán)來做登錄控制。(隱秘程度:高;重要程度:中)
<exclusion> <artifactId>spring-asm</artifactId> <groupId>org.springframework</groupId> </exclusion>
6、萬惡的測試環(huán)境字節(jié)碼驗(yàn)證失敗
之前發(fā)過一個(gè)前項(xiàng)目改造的spring boot項(xiàng)目就出現(xiàn)過,當(dāng)時(shí)不以為意,讓jvm參數(shù)加了-noverify就沒管,后來發(fā)現(xiàn)很多項(xiàng)目都有這個(gè)問題,開始排查。之前看過jdk和aspectj有沖突的例子,就開始tree里搜a(bǔ)spectj,發(fā)現(xiàn)spring-boot-start-aop里引入了1.9.4版本的aspectjweaver,但是當(dāng)時(shí)因?yàn)閙aven helper提示它沖突,就把它排了,后重新排掉所有1.7版本的aspectj,引入1.9.4版本的,解決。(隱秘程度:高;重要程度:高)
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${aspectj.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>${aspectj.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> <exclusion> <artifactId>*</artifactId> <groupId>org.aspectj</groupId> </exclusion>
7、日志不能正常輸出問題
排除,日志橋接混亂,后臺(tái)配置的日志格式不支持了
<exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion>
Configuration: status: info Properties: Property: - name: log.level.console value: info - name: log.path value: /var/XXX/weXXX - name: project.name value: weXXX - name: log.pattern value: "%-d{yyyy-MM-dd HH:mm:ss SS} [%c]-[%p] %m%n" Appenders: Console: name: CONSOLE target: SYSTEM_OUT PatternLayout: pattern: ${log.pattern} RollingRandomAccessFile: - name: APP_FILE fileName: ${log.path}/${project.name}.log filePattern: "${log.path}/${project.name}-%d{yyyy-MM-dd}.log" PatternLayout: pattern: ${log.pattern} Filters: ThresholdFilter: - level: info onMatch: ACCEPT onMismatch: DENY Policies: TimeBasedTriggeringPolicy: modulate: true interval: 1 DefaultRolloverStrategy: max: 30 Loggers: Root: level: info AppenderRef: - ref: CONSOLE - ref: APP_FILE Logger: - name: app level: info additivity: false AppenderRef: - ref: CONSOLE - ref: APP_FILE
8、本地打包正常
測試或者線上環(huán)境打包失敗,查看wrap.log日志,本地配置文件使用線上,打包測試;
spring-boot-maven-plugin插件放在靠后位置,不然打包失敗;
<profile> <id>uat</id> <properties> <profileActive>UatXXX</profileActive> </properties> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>appassembler-maven-plugin</artifactId> <version>2.0.0</version> <configuration> <configurationDirectory>conf</configurationDirectory> <repositoryLayout>flat</repositoryLayout> <useWildcardClassPath>true</useWildcardClassPath> <daemons> <daemon> <id>${project.artifactId}</id> <mainClass>com.XXXX.Application</mainClass> <commandLineArguments> <commandLineArgument>--spring.profiles.active=${profileActive} </commandLineArgument> </commandLineArguments> <platforms> <platform>jsw</platform> </platforms> <jvmSettings> <!-- 啟動(dòng)內(nèi)存配置 --> <initialMemorySize>2048M</initialMemorySize> <maxMemorySize>2048M</maxMemorySize> <maxStackSize>128</maxStackSize> <systemProperties> <systemProperty>application.root=.</systemProperty> <systemProperty>spring.application.name=${project.artifactId} </systemProperty> <systemProperty>spring.config.location=./conf/${profileActive}/ </systemProperty> </systemProperties> <extraArguments> <extraArgument>-XX:MetaspaceSize=256M</extraArgument> <extraArgument>-XX:MaxMetaspaceSize=256M</extraArgument> <extraArgument>-XX:+UseG1GC</extraArgument> <extraArgument>-XX:-OmitStackTraceInFastThrow</extraArgument> <extraArgument>-XX:MaxGCPauseMillis=100</extraArgument> <extraArgument>-XX:+ParallelRefProcEnabled</extraArgument> <extraArgument>-XX:+HeapDumpOnOutOfMemoryError</extraArgument> <extraArgument>-XX:+PrintCommandLineFlags</extraArgument> <extraArgument>-XX:+PrintGCDetails</extraArgument> <extraArgument>-XX:+PrintGCDateStamps</extraArgument> <extraArgument>-verbose:class</extraArgument> <extraArgument>-XX:+PrintClassHistogramBeforeFullGC</extraArgument> <extraArgument>-XX:+PrintClassHistogramAfterFullGC</extraArgument> <extraArgument>-XX:+PrintTenuringDistribution</extraArgument> <extraArgument>-XX:+PrintHeapAtGC</extraArgument> <extraArgument>-XX:+PrintGCApplicationStoppedTime</extraArgument> <extraArgument>-XX:+PrintGCApplicationConcurrentTime</extraArgument> <extraArgument>-Xloggc:/var/log/${project.artifactId}/gc-%t</extraArgument> <extraArgument>-XX:+UseGCLogFileRotation</extraArgument> <extraArgument>-XX:GCLogFileSize=10M</extraArgument> <extraArgument>-XX:NumberOfGCLogFiles=10</extraArgument> <extraArgument>-javaagent:/opt/jars/aspectjweaver-1.8.9.jar</extraArgument> </extraArguments> </jvmSettings> <generatorConfigurations> <generatorConfiguration> <generator>jsw</generator> <includes> <include>linux-x86-64</include> <include>macosx-universal-64</include> </includes> <configuration> <property> <name>configuration.directory.in.classpath.first</name> <value>conf</value> </property> <property> <name>wrapper.ping.timeout</name> <value>60</value> </property> <property> <name>set.default.REPO_DIR</name> <value>lib</value> </property> <property> <name>wrapper.logfile</name> <value>/var/XXXX/${project.artifactId}/wrapper.YYYYMMDD.log</value> </property> <property> <name>wrapper.logfile.rollmode</name> <value>DATE</value> </property> <property> <name>wrapper.logfile.maxfiles</name> <value>10</value> </property> <property> <name>wrapper.pidfile</name> <value>/var/XXXX//${project.artifactId}</value> </property> <property> <name>wrapper.java.command</name> <value>/usr/local/jdk8/bin/java</value> </property> <property> <name>wrapper.disable_restarts</name> <value>TRUE</value> </property> <property> <name>wrapper.jvm_exit.timeout</name> <value>5</value> </property> <property> <name>wrapper.shutdown.timeout</name> <value>5</value> </property> <property> <name>wrapper.cpu.timeout</name> <value>0</value> </property> </configuration> </generatorConfiguration> </generatorConfigurations> </daemon> </daemons> </configuration> <executions> <execution> <id>generate-jsw</id> <phase>package</phase> <goals> <goal>generate-daemons</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptors> <descriptor>src/main/assembly/assembly.xml</descriptor> </descriptors> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring.boot.version}</version> <executions> <execution> <goals> <goal>build-info</goal> </goals> <configuration> <additionalProperties> <encoding.source>UTF-8</encoding.source> <encoding.reporting>UTF-8</encoding.reporting> <java.source>${java.version}</java.source> <java.target>${java.version}</java.target> </additionalProperties> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile>
tips:
1、不要太相信maven helper提示的jar沖突,具體還是要具體分析
2、有些jar沖突網(wǎng)上容易查到,有些基本查不到,可以先去tree搜個(gè)短名看看,看看有沒有相似的jar,再去查是否真的會(huì)有沖突
3、有些是class沖突,找到對(duì)應(yīng)的jar排掉即可,盡量別排spring自帶的,容易出現(xiàn)兼容性問題
4、啟動(dòng)時(shí),我已經(jīng)將一些不必須的autoConfigure排掉了,真要用到,記得放出來,平時(shí)用不到的盡量排掉,這樣就不會(huì)去加載了,不然很多都是默認(rèn)加載的。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://blog.csdn.net/qq_40910788/article/details/105031208