jar package Conflict is a common problem in large-scale
Java software development, and system developers often spend a lot of time debugging and
testing to solve similar problems, in this paper, according to various situations, combined with
WebSphere in this paper, we discuss several methods to solve the problem of jar package conflict, and give the concrete implementation steps and source code.
The reader is positioned as a developer with Java and WebSphere development experience.
Readers can
learn about the definition of class loaders in WebSphere and how to resolve jar package conflicts, and can use the Java code provided in the article directly to save their development and commissioning time and improve efficiency.
In large-scale WebSphere-based project development, the same WebSphereApplication
Server(hereinafter referred to as wasMultiple applications are deployed, and these applications will inevitably share some jar packages, including tools provided by third parties and public jars within the project. By extracting these common jar packages and sharing them across multiple applications, you can not only maintain these jar packages uniformly, but also improve wasThe performance. But as applications continue to grow and new applications grow, new applications will want to use some later versions of shared jar packages, and because of the need for system maintenance, older applications still want to use older versions of shared jar packages, which inevitably create conflicting versions of shared jar packages. Jar Package version Conflict problem is a common problem in the development of large-scale application projects, this article attempts to start with the WebSphere ClassLoader, and discusses several ways to solve the problem of jar package conflict in different situations.
Introduction to the class loader in WebSphere
The jar package conflict is actually that the application will not be able to find the real required class while it is running, and the class loader (class loader) in the JVM and in WebSphere is affected by the discovery and loading of the classes, so let's start by introducing the class loader in WebSphere and some related concepts.
class loader hierarchy in WebSphere
When a Java application runs, it must be loaded through the ClassLoader to make it valid before class is executed and accessed, and the ClassLoader is part of the JVM code that is responsible for locating and loading all Java classes and local Lib libraries in the JVM virtual machine. Different Class loadersConfigurationAffects the behavior of the application when it is deployed to the runtime on the application server. JVM and WebSphere Application servers offer a variety of different classloaderConfiguration, forming a hierarchical structure with a parent-child relationship. The class loader hierarchy in WebSphere is shown in Figure 1:
hierarchy of Class loaders in Figure 1:websphere
As shown, the class loader in WebSphere is organized into a top-down hierarchy, the topmost of which is the system's running environment JVM, the bottom level is the specific application, and the parent-child relationship is formed between the upper and lower layers.
- JVM class loader: At the top of the entire hierarchy, it is the root of the entire ClassLoader hierarchy, so it does not have a parent classloader. This classloader is responsible for loading the JVM class, the JVM extension class, and all Java classes defined on the CLASSPATH environment variable.
- The WebSphere Extensions class Loader:websphere Extension class loader, which loads WebSphere runtime classes, resource adapter classes, and so on.
- The WebSphere Lib/app class Loader:websphere server class loader, which loads the classes on the path of the WebSphere installation directory under the $ (was_home)/lib/app. In the was V4 version, was uses this path to share jar packages across all applications. Starting with was V5, the shared library feature provides a better way, so the ClassLoader is primarily used for compatibility with some legacy systems.
- The WebSphere "Server" class Loader:websphere Application Server ClassLoader. It defines the classes that are shared among all the applications on this server. With the concept of shared libraries in was V5, you can define multiple ClassLoader associated with the shared library for the application Server , which form a parent-child relationship in the order in which they are defined.
- Application Module class Loader: The Application class loader, located at the last level of the hierarchy, for loading the Java EE application. Depending on the application's class loading strategy, you can also define your own class loader for the Web module.
With regard to the hierarchy of the WebSphere ClassLoader, the following notes may be more helpful in understanding the lookup and loading process of a class:
- Each class loader is responsible for finding and loading classes on its own defined classpath.
- A subclass loader can delegate its parent ClassLoader to find and load classes, and a request to load a class is sent from the subclass loader to the parent ClassLoader, but never from the parent class loader to the child ClassLoader.
- Once a class is loaded successfully, the JVM caches the class until its lifecycle ends and associates it with the appropriate classloader, which means that different classloader can load classes of the same name.
- If a loaded class relies on another or some class, then these dependent classes must exist on the class loader lookup path for the class, or the parent ClassLoader looks for the path.
- If a class loader and all of its parent ClassLoader cannot find the desired class, the system throws an Classnotfoundexecption exception or noclassdeffounderror error.
delegate mode for class loader
The ClassLoader has an important property: the delegate pattern (delegation mode, sometimes called load mode: Classloader mode). The delegate mode determines whether the ClassLoader finds a class by looking for the classpath specified by the ClassLoader itself or the classpath on the parent class loader first.
The class loader's delegate mode has two values:
- Parent_first: When loading a class, first try to find and load the class on the classpath of the parent class loader before looking for the load class from the class loader's own classpath.
- Parent_last: When loading a class, first try to find the load class from its own classpath, and then try the parent ClassLoader classpath if it is not found.
With the concept of a delegate pattern, we can more flexibly configure how classes are loaded and looked up in the class loader hierarchy. Table 1 shows the definition of the delegate pattern for each class loader in the WebSphere ClassLoader hierarchy, and gives the life cycle of classes within different classloader.
Note: In the table above, "JVM class loader" because at the top of the ClassLoader, it has no parent classloader, so its delegate mode is N/A, "WebSphere Extensions Class loader" and "WebSphere Lib/app The delegate mode of class loader is fixed to the value in the table, not configurable, and the delegate mode of the other classloader can be configured.
class loader policy in WebSphere
There are some related configurations for the ClassLoader in WebSphere, called ClassLoader policies (class loader policy). The ClassLoader policy refers to the class loader's stand-alone policy (class loader isolation policy), and we can define the class loader for was and the application independently, through the ClassLoader policies setting.
Each of the was can configure its own application class loader policy, and each application in was can also configure its own web module ClassLoader policy, as described in the following two strategies.
1. Application Server (WAS) configuration: Application class loader policy
The application server has two configurations for the application ClassLoader policy:
- Single: All applications on the entire application server use the same classloader. In this configuration, each application no longer has its own classloader.
- Multiple: Each application on the application server uses its own classloader.
2. Application Configuration: Web module class loader policy
There are two configurations for the Web module class loader in your application:
- Application: All utility jar packages and Web modules within the entire application use the same classloader.
- Module: Each Web module within the application uses its own classloader. The class loader for the application still exists and is responsible for loading classes other than the Web module in the application, including all utility jar packages.
As can be seen from the above definition, some class loaders on the class loader hierarchy may not exist under the configuration of the different ClassLoader policies. For example, in the case where the application ClassLoader policy of the application server is defined as single, the class loader for the application will not exist, and all applications on the same application server will share the same classloader, which means that the classes between the different applications are shared, A class with the same name cannot exist between applications
Resolving jar package conflicts in WebSphere
The jar package conflict problem is actually a class in a certain version of the jar package that the application wants to use, but the ClassLoader finds and loads the classes in another version of the jar package. After describing the basic concepts and related configuration of the class loader in WebSphere in the previous section, let's look at how to resolve jar package conflicts in WebSphere.
Before the was V5 version, the shared jar was used in the same way that the jar package was placed under the $ (was_home)/lib/app path, as we can see from the previous section that this path is "WebSphere Lib/app Class Loader" The class loader class finds the path, and WebSphere looks for the path to get the Java class in the corresponding jar package so that the jar package is shared between multiple applications on the WebSphere nd. However, one drawback of this is that these shared jar packages are exposed to all applications on WebSphere nd, and for those applications that wish to use the other versions of the jar package, these jar packages also exist on their classloader classpath, thus inevitably causing version conflicts. In the was V5 version and later, the concept of shared libraries was added, and the recommended way to share jar packages across multiple applications and avoid jar package collisions was to use shared libraries.
Specific analysis of the case of Jar packet conflict, there are three main types:
- Jar package conflicts between multiple applications: Jar version conflicts between multiple applications due to the use of different versions of the shared jar package.
- Jar package conflicts between multiple Web modules in an application: Inside the same application, different Web modules use different versions of a jar package to create a jar version conflict.
- Jar package conflicts within the same Web module in the application: Inside the same application, within the same Web module, the jar package conflicts caused by the need to use two versions of the same jar package simultaneously
This section discusses three ways to resolve jar package conflicts based on these three jar-pack conflicts, and discusses the implementation steps and applicability of the three solutions in detail:
- Resolve jar package conflicts with shared libraries: primarily addressing jar package conflicts between applications
- Package in a Web module to resolve jar package conflicts: Primarily addressing jar package conflicts between multiple Web modules in an application
- Command line run to resolve jar package conflicts: Primary solution for jar package conflicts within the same Web module in the application
Resolve jar Package conflicts by shared library mode
In was V5, a good mechanism was provided to make the jar package exist only on the path of the ClassLoader of the application that needs the jar package, while the other applications are unaffected by it, which is the shared library. Shared libraries can be used at the application server level and at the application level, using an application-level shared library, with the benefit of using different versions of shared jar packages between different applications. We can define a different shared library for each of the different versions of the common Jar package, and which version the application wants to use to place this version of the shared library on the classpath of the application's ClassLoader, which effectively solves the problem of jar package collisions between applications.
The following is an example of how to define and use a shared library, in this case, suppose there are Xerces.jar package version conflicts.
1. Defining shared libraries
System
Management Members can define shared libraries in the WebSphere Admin console, which can be defined at the cell, node, and server levels, respectively.
- Step one: Go to admin Console and select Environment > Shared Library > New. 2 is shown below:
Figure 2:websphere Admin Console to access the shared library page
- Step two: Give the name of the shared library and specify the shared files and directories. Multiple different files/directories are separated by the "Enter" key and cannot have path separators, such as ":" and ";" such as 3 is shown below:
Figure 3:websphere Admin Console Add a shared library
- Step three: After clicking Apply or OK, a shared library named Xerces V2.0 is added. Remember to save the configuration in the Admin console when you are done adding. 4 is shown below:
Figure 4:websphere Admin Console list of shared libraries
2. Install the application
Go to admin console and select the Applications > install NEW Application Installation application. Please refer to
IBMWebSphere Admin Console uses the manual to install new applications, which are no longer detailed here.
3. Associating a shared library to an application
- Step one: Go to admin console, select Applications >EnterpriseApplications, and select the application that needs to use the shared library. Note: Because you want to change the settings of your application, if your application is already running, you need to first stop the application. 5 is shown below:
Figure 5:websphere Admin Console Select the application you want to configure
- Step Two: Click on the application, enter after, select libraries. 6 is shown below:
Figure 6:websphere Admin Console Select the Application library properties
- Step Three: Click Add to add a shared library to your application. 7 is shown below:
Figure 7:websphere Admin Console Application Add library
- Step four: Select the desired shared library from the drop-down list and click OK. 8 is shown below:
Figure 8:websphere Admin Console in the Application Add Library page Specify the shared library used
In this way, the Xerces version of the Xerces V2.0 shared library definition exists on the class loading path of the application class loader. Note that you want to save the server's settings after the add is complete.
4. Set the application's class loader's delegate mode to Parent_last
To further prevent other versions of the jar package defined by the shared library from being present on the JVM or the WebSphere ClassLoader path, you also need to set the application's class loader delegate to Parent_last.
- Step one: Go to admin console, select Applications > Enterprise applications >, select the application you want to configure. 9 is shown below:
Figure 9:websphere Admin Console Select the application you want to configure
- Step two: Click into the application, set the class loader's delegate mode to Parent_last. Note: After the configuration is complete, you want to save the configuration and finally start the application. 10 is shown below:
Figure 10:websphere Admin Console to set the ClassLoader delegate mode for the application
With the above configuration, even if other versions of Xerces already exist in the system, the ClassLoader will first find and load the Xerces version in the specified shared library when the application is running. This allows us to resolve the issue of jar version conflicts by using shared libraries.
package in a Web module to resolve jar package conflicts
The way to share a library is only at the level of the application that resolves the version conflict problem that is caused by the shared jar between multiple applications, and if one of the internal applications uses a version of a jar package, and the other Web module uses the B version of the JAR package, In this case, the jar package conflict, the way to share the library is not resolved, we can consider one of the multiple applications to share a jar package version, such as a version, defined as a shared library, or placed in "WebSphere Lib/app Class Loader" The ClassLoader path is used by multiple applications, and the B version of the jar package is packaged into a Web module that uses it to resolve the conflict.
Second, many of the current online systems are legacy systems of was V4, which run applications that have used the "WebSphere Lib/app class loader" ClassLoader to share the jar package in the $ (was_home)/lib/app directory. If one of the applicationsUpgradeOr, to add a new application, you need to use a different version of a shared jar package, in which case, to reduce the impact on the system, you might also consider packaging a new version of the shared jar package intoUpgrade(or add) the way in the application to resolve jar package conflicts.
Because the Web module's Webcontent/web-info/lib directory is located on the application Web module's ClassLoader lookup path, we can place the jar package in this directory, and the class loader of the Web module will automatically find and load the classes in the jar package.
- Step one: in Wsad IE integrated development environment, the conflict jar package is placed in the Webcontent/web-info/lib directory of the WEB module. 11 is shown below:
Figure 11:wsad Add a library to the Web module in IE
- Step two: In the admin console, after deploying the application to WebSphere server, go to Applications > Enterprise applications, select the appropriate application, and verify that the application is not running (See the procedure for selecting an application in the previous section.) Click Enter application to confirm that the application's class loader's delegate mode is Parent_first, and the application's ClassLoader policy is module. 12 is shown below:
Figure 12:websphere Admin Console in the Application Properties configuration page
- Step three: On the same page, select Web Modules, click Enter. 13 is shown below:
Figure 13:websphere Admin Console Select the Application Web module properties
- Step four: Click the appropriate Web module that contains the conflict jar package, and set the delegate mode of the Web module's ClassLoader to Parent_last. Note: After the setup is complete, save the server configuration and start the application. 14 is shown below:
Figure 14:websphere Admin Console specifying the ClassLoader delegate mode for the Web module
Package The conflict jar package into a Web module and set the delegate mode of the class loader for the appropriate Web module to Parent_last, when the application loads the class while it is running, the ClassLoader of the Web module first looks for the webcontent/web-info/ The jar packages in the Lib directory are loaded for classes, and for other web modules, because the delegate mode of their classloader is still the default Parent_first, their classloader still first loads the classes in the jar package from the application's shared library or from the WebSphere shared path. This solves the problem of jar package conflict.
command line run to resolve jar package conflicts
Whether you set up a shared library or package a conflict jar package into an application, it solves the problem of using only one version of the conflicting jar package in one of the application's Web modules. We have encountered this situation in development: The application's Web module has been used in the 1.4 version of Xerces.jar, due to the extension of the Web function, in this module introduced a new third-party tool, and this third-party tool needs to use 2.0 version of Xerces.jar to work properly, in this case the How can jar package conflicts be resolved?
As already described in the previous Class loader section, one Web module per application can have at most one classloader, whereas the life cycle of the class loaded in the Web module's ClassLoader is the entire application's runtime, meaning that the Web module loader cannot load two versions of one class at a time, and The delegate mode of the Web module's ClassLoader is also set before the application runs and cannot be changed during the application's run time, so the above description of the two-version jar package is used in a Web module. The way to configure the setup of a classloader that runs within a JVM is not resolved as in the first two methods.
The only solution is to start another JVM to run the code that invokes the conflicting jar package outside of the JVM that the application is running, since two different JVMs can load their classes to resolve the jar package conflict.
In this case, the original way of using the old version of the jar package (including the jar package placement path, shared library settings, class loader delegate mode, etc.) is unchanged, the call to the new version of the jar package is implemented by the command line. This is done by encapsulating the invocation of functionality within the new version of the jar package into a class that can be run separately and running the class as a command line in the Web module. At the same time, put the new version of this class and the jar package on any path that was accessible (such as/usr/websphere), including the path in the command line's classpath parameter (such as/usr/websphere).
The following is an example of how the command line runs, in this example, assuming that Conflict_v1.jar is already in use in the Web module Testwar of the Testear application, as new additions are required to use conflict_ The Examplecall () feature in V2.jar.
Conflict Jar Package Conflict_v2.jar provides the functionality:
Code Listing 1: conflict jar Package Conflict_v2.jar feature
Package Com.ibm.conflictublic class conflictclass{... public static string Examplecall (string param) {string rs; ...; Return rs;} ......} |
Examples of encodings when there are no conflicting issues:
If there is no jar-package conflict problem, then the call to this feature is simple, just put Conflict_v2.jar on the application itself or its parent ClassLoader's lookup path, and then call it directly in the Web module, as follows:
Code Listing 2: How to call when there is no conflict
public string MethodA (string param) {... String rs = conflictclass.examplecall (param); ...... Return rs;} |
Example of a command line run as code after a conflict
For the jar package conflict, we need to make the following modifications in the Web module:
- Step One: Place the conflict jar package on the path that was is accessible, such as/usr/websphere/conflict_v2.jar.
- Step two: Encapsulate the calls that contain the conflicting code into a set of classes that can be run individually, and they will invoke the functionality of the conflicting jar package and print the results to the system standard output in the way the system outputs. Encapsulate these classes in a separate jar file, such as Workaroundconflict.jar, and place them on a path that was accessible, such as/usr/websphere/workaroundconflict.jar.
Package Com.ibm.test;import Com.ibm.ConflictClassublic class Workaround{public static void Main (string[] args) {String Param1=args[0]; String Returnstr=conflictclass.examplecall (); System.out.println ("<RTStr>" +returnstr+ "</RTStr>"); Return;}} |
Code Listing 3: Writes a call to the conflicting code to a separate class workaround
- Step three: Call the encapsulated class through the command line in the Web module, specifying all the dependent jar packages and classpath through Classpath. Run the wrapper class to get the results from the system standard output.
public static string MethodA (string param) {... String rtstr = ""; String lstr= "<RTStr>"; String rstr= "<RTStr>"; Put all the dependency jar here String classpath= "/usr/websphere/conflict_v2.jar; /usr/websphere/workaroundconflict.jar, ... "; String classname= "Com.ibm.test.WorkAround"; String cmdline= "Java-classpath" +classpath + "+classname +" "+ param; try{ProcessProcess = Runtime.getruntime (). exec (Cmdline,null); Process.waitfor (); BufferedReader br= New BufferedReader (New InputStreamReader (Process.getinputstream ())); while ((s = br.readline ())!=null) {if (null = = out) ut=s; else Out+=s;} Get result from outif (null! = out) {int lIndex = Out.lastindexof (lstr), int rindex = Out.lastindexof (rStr); rsstr = out . substring (lindex+lstr.length, rindex);} } catch (Exception e) {e.printstacktrace ();} ..... return rsstr;} |
Code Listing 4: Running workaround in the application from the command line
The command line runs by running the conflicting code in a different JVM, loading the conflicting class, and resolving the jar package conflict.
But the command-line operation is not a good way after all, it has the following drawbacks:
- The command line runs only for situations where the use of a conflicting jar package only runs a piece of code, or only requires a simple string result to be returned. For complex interactions, the command-line approach cannot be done. However, if there is no other way, it is appropriate to encapsulate the containment scope of the jar package called by the conflict Code, and try to simplify the code interface that the command line runs.
- The command-line run mode reduces WebSphere performance because it starts another JVM to run.
Therefore, the command-line approach only works in some extremely special cases to resolve jar package conflicts.
Conclusion
In this paper, the problem of jar-package conflict in the development of large-scale project based on WebSphere, combined with the concept of class loader in WebSphere, three kinds of solutions and corresponding operation steps and implementation code are given, and the specific situations which are applied in various ways are analyzed.
There are three main cases of jar package conflicts during project development:
- Jar package conflicts between multiple applications
- Jar package conflicts between multiple Web modules within an application
- Intra-application jar package conflicts within the same Web module
Through the analysis of the ClassLoader, we know that the root of the problem of solving jar package conflicts is to properly configure the ClassLoader. Based on an in-depth understanding of the hierarchical structure of the class loader in WebSphere, we give a "shared library to resolve jar package conflicts" and "package to the Web module to resolve jar package conflicts" approach, through the rational configuration of the WebSphere class loader and its delegate mode, Can resolve most jar package conflict issues. However, because the class loader in this hierarchy is only configured to the Web module, the configuration of the ClassLoader is not resolved for the problem of jar package conflicts inside the Web module, so we give the method of "command line run to resolve jar package conflict".
Table 2 lists the jar package conflicts that apply to the three ways to resolve the jar package conflict problem under the different versions of was.
Table 2:jar Packet Conflict resolution applicable JAR package conflict situation Summary