1. 循环依赖问题
Maven中如果出现:
A 依赖 B
B 依赖 A
就会导致Maven Compile AssertionError:
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ xxx ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 302 source files to /Path
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.124 s (Wall Clock)
[INFO] Finished at: 2021-11-12T10:12:25+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] AssertionError -> [Help 1]
java.lang.AssertionError
at com.sun.tools.javac.util.Assert.error (Assert.java:155)
at com.sun.tools.javac.util.Assert.check (Assert.java:46)
at com.sun.tools.javac.comp.Modules.enter (Modules.java:247)
at com.sun.tools.javac.main.JavaCompiler.readSourceFile (JavaCompiler.java:837)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$ImplicitCompleter.complete (JavacProcessingEnvironment.java:1530)
at com.sun.tools.javac.code.Symbol.complete (Symbol.java:642)
at com.sun.tools.javac.code.Symbol$ClassSymbol.complete (Symbol.java:1326)
at com.sun.tools.javac.code.Type$ClassType.complete (Type.java:1140)
at com.sun.tools.javac.code.Type$ClassType.getTypeArguments (Type.java:1066)
at com.sun.tools.javac.code.Printer.visitClassType (Printer.java:237)
at com.sun.tools.javac.code.Printer.visitClassType (Printer.java:52)
at com.sun.tools.javac.code.Type$ClassType.accept (Type.java:993)
at com.sun.tools.javac.code.Printer.visit (Printer.java:136)
at com.sun.tools.javac.util.AbstractDiagnosticFormatter.formatArgument (AbstractDiagnosticFormatter.java:199)
at com.sun.tools.javac.util.AbstractDiagnosticFormatter.formatArguments (AbstractDiagnosticFormatter.java:167)
at com.sun.tools.javac.util.BasicDiagnosticFormatter.formatMessage (BasicDiagnosticFormatter.java:111)
at com.sun.tools.javac.util.BasicDiagnosticFormatter.formatMessage (BasicDiagnosticFormatter.java:67)
at com.sun.tools.javac.util.AbstractDiagnosticFormatter.formatArgument (AbstractDiagnosticFormatter.java:185)
at com.sun.tools.javac.util.AbstractDiagnosticFormatter.formatArguments (AbstractDiagnosticFormatter.java:167)
at com.sun.tools.javac.util.BasicDiagnosticFormatter.formatMessage (BasicDiagnosticFormatter.java:111)
at com.sun.tools.javac.util.BasicDiagnosticFormatter.formatMessage (BasicDiagnosticFormatter.java:67)
at com.sun.tools.javac.util.JCDiagnostic.getMessage (JCDiagnostic.java:788)
at com.sun.tools.javac.api.ClientCodeWrapper$DiagnosticSourceUnwrapper.getMessage (ClientCodeWrapper.java:799)
at org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess (JavaxToolsCompiler.java:131)
at org.codehaus.plexus.compiler.javac.JavacCompiler.performCompile (JavacCompiler.java:174)
at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute (AbstractCompilerMojo.java:1134)
at org.apache.maven.plugin.compiler.CompilerMojo.execute (CompilerMojo.java:187)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:202)
at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:198)
at java.util.concurrent.FutureTask.run (FutureTask.java:264)
at java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:515)
at java.util.concurrent.FutureTask.run (FutureTask.java:264)
at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:628)
at java.lang.Thread.run (Thread.java:829)
[ERROR] java.lang.AssertionError
java.util.concurrent.ExecutionException: java.lang.AssertionError
at java.util.concurrent.FutureTask.report (FutureTask.java:122)
at java.util.concurrent.FutureTask.get (FutureTask.java:191)
at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder.multiThreadedProjectTaskSegmentBuild (MultiThreadedBuilder.java:142)
at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder.build (MultiThreadedBuilder.java:103)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956)
at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:288)
at org.apache.maven.cli.MavenCli.main (MavenCli.java:192)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke (Method.java:566)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
at org.codehaus.classworlds.Launcher.main (Launcher.java:47)
Caused by: java.lang.AssertionError
at com.sun.tools.javac.util.Assert.error (Assert.java:155)
at com.sun.tools.javac.util.Assert.check (Assert.java:46)
at com.sun.tools.javac.comp.Modules.enter (Modules.java:247)
at com.sun.tools.javac.main.JavaCompiler.readSourceFile (JavaCompiler.java:837)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$ImplicitCompleter.complete (JavacProcessingEnvironment.java:1530)
at com.sun.tools.javac.code.Symbol.complete (Symbol.java:642)
at com.sun.tools.javac.code.Symbol$ClassSymbol.complete (Symbol.java:1326)
at com.sun.tools.javac.code.Type$ClassType.complete (Type.java:1140)
at com.sun.tools.javac.code.Type$ClassType.getTypeArguments (Type.java:1066)
at com.sun.tools.javac.code.Printer.visitClassType (Printer.java:237)
at com.sun.tools.javac.code.Printer.visitClassType (Printer.java:52)
at com.sun.tools.javac.code.Type$ClassType.accept (Type.java:993)
at com.sun.tools.javac.code.Printer.visit (Printer.java:136)
at com.sun.tools.javac.util.AbstractDiagnosticFormatter.formatArgument (AbstractDiagnosticFormatter.java:199)
at com.sun.tools.javac.util.AbstractDiagnosticFormatter.formatArguments (AbstractDiagnosticFormatter.java:167)
at com.sun.tools.javac.util.BasicDiagnosticFormatter.formatMessage (BasicDiagnosticFormatter.java:111)
at com.sun.tools.javac.util.BasicDiagnosticFormatter.formatMessage (BasicDiagnosticFormatter.java:67)
at com.sun.tools.javac.util.AbstractDiagnosticFormatter.formatArgument (AbstractDiagnosticFormatter.java:185)
at com.sun.tools.javac.util.AbstractDiagnosticFormatter.formatArguments (AbstractDiagnosticFormatter.java:167)
at com.sun.tools.javac.util.BasicDiagnosticFormatter.formatMessage (BasicDiagnosticFormatter.java:111)
at com.sun.tools.javac.util.BasicDiagnosticFormatter.formatMessage (BasicDiagnosticFormatter.java:67)
at com.sun.tools.javac.util.JCDiagnostic.getMessage (JCDiagnostic.java:788)
at com.sun.tools.javac.api.ClientCodeWrapper$DiagnosticSourceUnwrapper.getMessage (ClientCodeWrapper.java:799)
at org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess (JavaxToolsCompiler.java:131)
at org.codehaus.plexus.compiler.javac.JavacCompiler.performCompile (JavacCompiler.java:174)
at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute (AbstractCompilerMojo.java:1134)
at org.apache.maven.plugin.compiler.CompilerMojo.execute (CompilerMojo.java:187)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:202)
at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:198)
at java.util.concurrent.FutureTask.run (FutureTask.java:264)
at java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:515)
at java.util.concurrent.FutureTask.run (FutureTask.java:264)
at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:628)
at java.lang.Thread.run (Thread.java:829)
[ERROR]
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/AssertionError
在多模块项目中要尤其注意模块之间的依赖情况,避免循环依赖。
2. API包如何打包给其他服务引入
我们的多模块中有一个API模块/Client模块(COLA),这个模块是需要deploy到私服上让其他服务引入进行使用的,这里有一些注意点。
2.1. 在父POM中进行Deploy操作
一般,我们的多模块可能是这样:
root.pom
- api-module.pom
- ....其他模块pom
例中的api-module.pom就是我们的API模块,但如果单独deploy api模块的话,可能在实际使用时会报错,找不到parent pom,也就是例中的root.pom。 因此,需要在父pom执行Deploy操作,这样可以将root.pom和api模块一起部署到私服上。 当然,这里可能会连带其他模块一起deploy上去,如果不需要的话,可以使用下面的方式跳过:
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
2.2. 如果API包的配置了spring-boot-maven-plugin需要注意
一般情况API包不会引入spring-boot-maven-plugin,但是不排除一些父POM中依赖传递下来的情况,因此,如果API包的父POM中配置了SpringBoot的Maven插件:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
......
</plugin>
你可能会遇到打出来的包无法被其他服务引入,或者即使引入也无法使用包中的class,这是因为引入了SpringBoot的Maven插件后,如果goal配置repackage,会在maven package阶段,对打包后的jar进行二次打包,打包成SpringBoot的可执行Jar包,无法被其他服务作为普通jar包引入。 解决方式有2个:
- 阻止SpringBoot进行repackage(因为API包本身也不应该是一个可执行Jar):
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<phase>none</phase>
</execution>
</executions>
......
</plugin>
</plugins>
- 配置classifier参数,这样SpringBoot打包出会有两个jar包(一个普通Jar包,一个SpringBoot可执行Jar包)
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<file>maycur-sampling-review-service-client-${project.version}.jar</file>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
如果使用第二种方式,还需要指定一下Deploy的jar包避免将SpringBoot的可执行Jar部署到私服上:
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<file>artifactId-${project.version}.jar</file>
</configuration>
</plugin>
</plugins>
3. SpringBoot的多模块项目如何启动
在多模块项目中,往往SpringBoot的启动类往往还是会放在某一个模块中,比如COLA架构中,是放在start模块下,其他依赖的模块通过maven dependencies的方式引入就可以。
3.1. 如果你的子模块中配置了spring-boot-maven-plugin需要注意
这个同2.2,也是需要调整spring-boot-maven-plugin相关配置,避免报错。
4. 运维相关
多模块项目打包需要和运维协商好,这个各家公司不同。
5. 如果你想统一整个模块的版本号
可以使用一个占位字段properties属性,在parent的POM中用占位的方式去做:
<groupId>com.xx</groupId>
<artifactId>xx-parent</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<name>xx-parent</name>
<properties>
<revision>3.0.0-SNAPSHOT</revision>
</properties>
这里revision就是一个整体版本号的property,子模块中也可以使用。 不过,在打包时Maven会将“${revision}”这个作为version打包进去,也就无法被其他服务引入了,这里可以引入flatten-maven-plugin:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.1.0</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
这个插件的作用就是在install或者deploy的时候,生成一个新的替换占位符的pom文件,也就是帮你替换了这些变量,接着把新的pom文件打入到jar包里。