background

The first product is a SpringBoot project based on multi-module development. When released, multiple WAR packages are exported and deployed in the same Tomcat. There are five or six modules, and the biggest problem with the release is that each package is very large, mainly because the web-INF /lib of each module contains a large number of identical jars, so it is necessary to pull out the common package and put it in the Tomcat shared directory.

However, after two days of tinkering, I have doubts about Tomcat’s ability to share common packages for multi-application deployments. In theory, if multiple applications are deployed in the same Tomcat, you can put all shared jars in the shared/lib directory and configure shared.loader.

The practice, take the public package, multiple war deployment time is always an error, the WEB – under the INF/lib clearly has a corresponding Spring framework package, or report under Caused by: Java. Lang. NoClassDefFoundError: Org/springframework/beans/factory/FactoryBean abnormalities, repeated testing, still not sure which packages should be as a common package.

So, I decided to get to the bottom of the class loading process at its source and break point to track what was going on in the compiled version of Tomcat. First thing, compile the Tomcat source code.

Tomcat source code

The process of importing Tomcat source code into IDEA is relatively simple, and the steps are as follows:

  1. Download the ANT tool, latest version 1.10.9, and configure the environment variable ANT_HOME:

  1. Download the Tomcat source code and select the zip or tar.gz file based on the operating system.
  2. Go to the source directory and compile the source using the Ant command.

This operation takes a long time, wait patiently for the compilation to complete:4. Create a catalina-home directory and copy all the files in the output/build directory to the Catalina-home directory as the Tomcat working directory:

  1. Go to the source directory and create pom.xml to add dependencies:
<? The XML version = "1.0" encoding = "utf-8"? > < project XMLNS = "http://maven.apache.org/POM/4.0.0" XMLNS: xsi = "http://www.w3.org/2001/XMLSchema-instance" Xsi: schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion > 4.0.0 < / modelVersion > < groupId >. Org. Apache tomcat < / groupId > < artifactId > Tomcat8.0 < / artifactId > < name > Tomcat8.0 < / name > < version > 8.0 < / version > < build > < finalName > Tomcat8.0 < / finalName > <sourceDirectory>java</sourceDirectory> <! --<testSourceDirectory>test</testSourceDirectory>--> <resources> <resource> <directory>java</directory> </resource> </resources> <! --<testResources>--> <! --<testResource>--> <! --<directory>test</directory>--> <! --</testResource>--> <! --</testResources>--> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> < artifactId > maven -- the compiler plugin < / artifactId > < version > 3.1 < / version > < configuration > < encoding > utf-8 < / encoding > <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> Easymock </groupId> <artifactId>easymock</artifactId> <version>3.4</version> </dependency> <dependency> <groupId>ant</groupId> <artifactId>ant</artifactId> <version>1.7.0</version> </dependency> <dependency> GroupId > wsdl4J </groupId> <artifactId>wsdl4j</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>javax. XML </groupId> <artifactId> JAXrpc </artifactId> <version>1.1</version> </dependency> <dependency> Piler < groupId > org.eclipse.jdt.core.com < / groupId > < artifactId > ecj < / artifactId > < version > 4.5.1 < / version > < / dependency > </dependencies> </project>Copy the code
  1. Import IDEA source code and configure startup parameters-Dcatalina.home="F:\Study\TomcateStudy\2021Tomcat\catalina-home"

In general, compiling source code is relatively simple, but at the beginning, I randomly selected the latest version, which caused the failure to start. This may be a defect when the official website version was released, but there is no problem with changing the version.

The problem with the wrong version

First, in the MAC operating system, randomly select the latest version of Tomcat8.5.63 tar.gz, download, compile error. Error @version@:

Error:osgi: [Tomcat8. 5] Invalid value for Bundle-Version, @VERSION@ does not
Copy the code

After changing to a specific value, the following error is reported:

Initially suspected to be the IDEA configuration problem, so in the Windows operating system, or using the latest version of tomcat8.5.63 zip version download source code, configuration parameters are as follows:

Oddly enough, it compiles and works:Conclusion: there is a problem with the manifest.mf file generated by the JdbC-pool module package of the Tomcat8.5.63 tar.gz source code, which should be avoided when compiling source code. I thought it was the same, so I just picked the latest version, and then I got stuck.

Finally, switch to Tomcat8.5.59, and the MAC should start correctly.

Console garble problem

Finally solve the console garble problem, mainly involving two classes, they use the default encoding resulting in the output of garble. The detailed operations are as follows:

The first step is to modify the org, apache tomcat, util. Res., StringManager class get String (final String key, the final Object… Args) method, and then transcoding after obtaining value:

try{
     value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
 }catch (Exception e ){
     e.printStackTrace();
 }
Copy the code

. The second step, modify org.apache.jasper.com piler Localizer class getMessage (String errCode) method, before returning for transcoding:

 try{
     errMsg = new String(errMsg.getBytes("ISO-8859-1"),"UTF-8");
 }catch (Exception e ){
     e.printStackTrace();
 }
Copy the code

If you restart the Tomcat application, the output is normal:

The revelation of

The questions that have not been answered so far are:

  1. What are the principles for multi-application shared Lib?
  2. Which packages should be placed under shared/lib? [I will be pure third-party JAR, no related dependencies]
  3. Web-inf /lib contains the starter dependency of SpringBoot and only the jar of the application itself.