在可移动应用中工具类Jar文件打包机制探索

Many J2EE applications use utility classes or libraries that provide some extra functionality not supported by the application code or the J2EE platform APIs. Often these libraries are jarred up so they can be used by multiple applications. These jarred up libraries can be home-grown or obtained from a third party. An application using a library that is a provided to your application code is a common and valid use case for apps and is supported by J2EE.

If you are already familiar with the mechanisms in J2EE for portable packaging of library jar files, feel free to skip to the scenarios section where the mechanisms are applied to various application packaging scenarios.

Here are some common example use case scenarios:
1.    An application that uses Struts and its APIs to provide an MVC framework. The application code then depends on these Struts classes as well as the standard APIs provided by the J2EE application server. 
2.    An application uses JSTL so it has a jstl.jar files to provide some tags which are used by the application's JSP pages. 
3.    An application uses a logging utility which may be a third-party library jar or home-grown library jar. This logging utility is used by many different applications so is a separate jar file in order to be re-used.
Once you have decided to use one of these libraries, deciding how to package these extra libraries along with the application code is an important design decision. It can affect the portability of your application. It can affect the size of your war and ear files. It can affect the maintenance of the application and version control as libraries and application servers are updated. So the choice of how to handle these libraries has some important impacts.

Solution
For portable applications there are several mechanisms in J2EE to support using optional packages such as a jarred up library or utility. These mechanisms are reviewed briefly in the table below. For each of these mechanisms, you need to determine where to place the library jar file and how the referencing application jar(ear, war, etc) files can indicate where the library jar can be found(through an explicit reference or placed in well-known location such as WEB-INF/lib or J2SE lib/ext).

Overview of Mechanisms to support optional packages
There are some solutions that are application-server specific for packaging library jar files. For example, placing a library jar file in an application server's classpath so that applications can use the APIs that are in that jar file. Or some application servers have container specific locations where you can just drop jar files to be shared by applications and modules. But these mechanisms are application specific and are less favorable to using the portable mechanisms provided by J2EE. Lets take a brief look at the portable mechanisms for using optional packages such as library jar files. Some of these mechanisms are J2EE specific and some leverage the J2SE extension architecture mechanisms for handling optional packages. For a detailed description of these mechanisms, refer to the References section at the end of this document.

Note that some application servers allow for mechanisms beyond these portbale mechanisms. So often, just dropping a jar file in a certain location will allow an application to deploy and run even. But is is best to use the portable mechanisms described below.
Mechanism 1: The WEB-INF/lib directory
Just place a library jar file such as struts.jar into WEB-INF/lib and a web application or web module can use the struts APIs. This can only be used by web modules(war files). With this mechanism the library jar file is included as part of the war file. The WEB-INF/lib is a well-known location to find libraries and is supported by J2EE. Note that the library jar file is just scoped to the web module where it is is bundled inside the WEB-INF/lib directory and can not be shared by other modules or applications. This mechanism can not be used by EJB modules.
Mechanism 2: Bundled optional classes 
Use the Class-Path attribute and manifest file to reference a library jar file(s) that is included in the ear file. With this mechanism the library jar file is included as part of the referencing jar file(ear file), sometimes it is said the library is bundled. Since ear files and war files etc are JAR files they can leverage the JAR mechanisms to reference dependent jar files. A manifest file META-INF/MANIFEST.MF is included in the referencing jar file and in the manifest file the Class-Path attribute is included along with the module referencing the library jar being used. More than one library can be listed in the Class-Path. Class-Path is one of the Jar-file manifest attributes.

The J2EE 1.4 specification mentions that top-level JAR files, such as .ear files, should not contain Class-Path references since it would reference files external to the top-level JAR. With this mechanism, the library jar file should be bundled as part of the ear/war jar file and should not be external.

Here is an example for an ear file containing a web module that uses Struts:
application.ear: 
  META-INF/application.xml 
  struts.jar 
  webapp.war 
              META-INF/MANIFEST.MF:
                  Manifest-Version: 1.0
                  Class-Path: struts.jar 
               WEB-INF/web.xml 
Mechanism 3: Installed packages
Use the Extension-List attribute and manifest file to reference a library jar file(s) that is not bundled in the ear file but is  installed in some well-known location, usually the lib/ext of J2SE. With this mechanism the library jar file is *not* included as part of the ear file. The library jar file(s) referenced is external to the ear file and instead stored in install directory, where this external location is referenced using the Extension-List. In this case these are often called installed libraries. In the application ear file, the manifest file is used and the Extension-List attribute is used  to express its dependency on a library jar file. More than one library can be listed in the Extension-List. The applications will not deploy if the application server can not find the library and resolve the dependency. Extension-List is one of the Jar-file manifest attributes. This attribute indicates the optional packages that are needed.
Note, when using this installed packages mechanism, the library jar file is available to all applications.

Here is an example(from J2EE 1.4 spec) where util.jar is placed in the install directory lib\ext and util.jar is used by app1.ear application:
app1.ear:
      META-INF/application.xml
      ejb1.jar:
            META-INF/MANIFEST.MF:
                    Extension-List: util
                    util-Extension-Name: com/example/util
                    util-Extension-Specification-Version: 1.4
             META-INF/ejb-jar.xml

util.jar:
      META-INF/MANIFEST.MF:
               Extension-Name: com/example/util
               Specification-Title: example.com’s util package
               Specification-Version: 1.4
               Specification-Vendor: example.com
               Implementation-Version: build96
Brief description of  the J2SE 1.4 extensions for optional packages
The J2EE 1.4 mechanisms for portably packaging library jar files leverage the J2SE mechanisms for allowing applications to use jarred up libraries. So it might be useful to briefly review some of these concepts. Note that optional packages is the new term for what used to be known as standard extensions or just extensions.

Here are two ways that J2SE allows optional packages(these are paraphrased from the Optional Packages Overview document):
1.    Installed optional packages are JAR files located in the directory lib/ext [in the Java 2 Runtime Environment] or jre/lib/ext [in the Java 2 SDK]. The jar file should have a manifest file describing itself. 
2.    Download optional packages, also called bundled optional packages. A bundled/download optional package is a JAR files that is specified in the Class-Path header field in the manifest of another JAR files. Classes in download optional packages may be used by classes in the referencing JAR file. Unlike the case of installed optional packages, the location of the JAR files that serve as bundled/download optional packages is irrelevant. A download optional package is an optional package because it is specified as the value of the Class-Path header in another JAR file's manifest, not because it has any particular location.
Precedence Order
What if an application ear file uses more than one mechanism to reference a library in its packaging? Or what if multiple versions (or multiple copies of the same version) of a library jar file are present? Which instance of the jar file would be used at runtime by the application? Note the order of precedence in J2EE and J2SE may be different, and the J2EE specification applies to applications deployed on application servers. The J2EE specification recommends a precedence order for resolving the finding of an optional package. Generally an application server will look for a class in a library jar file in the order of precedence: first the WEB-INF/lib mechanism, then the bundled optional package mechanism, and then the installed optional package mechanism. If a class can not be found then the application should not be deployed. Also, note that application servers often will not let a library jar file replace a platform API, so for example an inclusion of your own servlet.jar file using one of these mechanisms will often be ignored. This is a safety precaution to avoid having mistakes alter the container behavior for standard platform APIs.

Scenarios
Now that we know the mechanisms for portably packaging an optional package jarred up as a a library JAR file, lets look at how they can be applied to some common scenarios for J2EE applications. These use cases are based on the questions and scenarios folks have been frequently asking about.  
Scenario:The application is a stand-alone war file that uses a library file(s).
When an application consists of a war file and does not intend to create an ear file. Note, in J2EE 1.4, a stand-alone module such as a war file is considered a valid J2EE application and no ear file wrapper is required.

In this case, you can use the WEB-INF/lib mechanism. Just include the struts.jar in the WEB-INF/lib directory of the war file, no other steps are required. The library jar file is packaged as part of the war file. A web application can add more library jar files used by an application in this manner. So if two or more libraries are used, then just include all the library jar files.

The bundled optional packages mechanism  would *not* work since the war file in this case is a top-level jar(a stand-alone war or .ear file) and top-level  jars should not have Class-Path attributes. It would imply something external to the top level jar instead of bundled inside it. 
 
The installed optional packages mechanism would work. For example, a library jar file such as struts.jar could be placed in the extensions directory. The application would need to include a manifest file and  indicate that it needs one or more optional packages using the Extension-List attributes. 
Scenario: The application is an ear file containing just one war file that uses a library jar file(s)
Many applications package everything into an ear file. Even for a simple application consisting of one war module, these can be packaged up into an ear file. In this scenario, the web module uses some library APIs so is dependent on the library jar file. The web module may use more than one library and have more than one library dependency.

For this case, you can use all three of the mechanisms. 
Scenario: The application is an ear file containing more than one web module(war files) and these wars each use library jar files
In this case, an ear file has multiple wars that use libraries. You might have war files that use different sets of libraries or  you might have wars that both use the same library.

You can use all 3 mechanisms. 
1.    (mechanism 1)For the WEB-INF/lib mechanism, each web module includes the library jar files it uses in the WEB-INF/lib of its war file. If there is a common library used by more than one war file then the common library will have multiple copies of its jar file, one for each war file using it. Each war file has its own copy, so in this case the other mechanisms might be preferred.
2.    (mechanism 2)For the bundled optional packages mechanism, each module has a manifest file that uses the Class-Path attribute to list all the library jar files that it is dependent on. The library jar file is placed within the ear file. You can have one copy of the library jar and all the web modules that use it can reference that library jar with the Class-Path attribute. 
3.    (mechanism 3)For the installed optional packages mechanism, each module uses the Extension-List attribute and manifest file to express all the libraries it is dependent on. In this case, the ear file does not contain the library jar file, instead the ear file just uses the manifest file to reference the installed extra libraries it uses.
Scenario: The application is an ear file containing  more than one web module(war files) and these web modules want to "share" the same library jar file and not have duplicate copies of the library.
Just want to cover this sharing case separately since it is asked about a lot. An example is an ear file with two war files both using struts and you want them to share the struts.jar instead of having duplicate copies.

You can use the bundled optional packages mechanism or the installed packages mechanism in this scenario. You can *not* use the WEB-INF/lib mechanism for sharing since in this mechanism each web module has its own copy of the library jar file.

For the bundled optional packages mechanism just have each web module use the manifest file and Class-Path attribute to point to the same location for the jar file bundled within the ear file. So this way there is just one copy of the library, such as struts.jar, that is included within the ear file. Otherwise each web module would have two copies of the library jar file and would not be sharing.

For the installed optional packages mechanism, just have each web module use a manifest file and Extension-List attribute to point to the same location of the library installed in the extensions directory, which is not included in the ear file. This way each application is sharing the same library jar file.
Scenario: Multiple applications(different ear files and/or different stand-alone war files ) want to "share" the same library jar file.
In this case you want multiple applications to use the same library and you dont want to include duplicate copies of the library jar file in each application. For example, multiple applications may need to use the same version of the JSTL tag libraries. This case covers applications that are deployed as ear files or applications that are deployed as stand-alone war files.

You can use the installed optional packages mechanism for this. Just put one copy of the library such as struts.jar in the extension directory location and in each application that uses struts APIs, use the manifest file and Extension-List attribute to express this dependency.
Scenario:For application ear files which have EJB module(s) and may or may not have a web layer
Applications can have EJBs that use some library jar files. Some ear files have EJB modules, web modules, etc. Some applications use EJBs but dont have a web tier, for example, a workflow engine designed using JMS and EJBs which has no presentation layer- a headless application. Both of these cases are the same for using and packaging the libraries used by the EJBs.  

For this case you can use the  the bundled optional packages mechanism and the installed optional packages mechanism. 
Scenario: For developers of libraries intended to be used and packaged with applications. 
All the other examples were use cases of an application using a library for a portable application. What if you are a developer of a library such as struts or JSTL or JSF and you want your library to be portable on J2EE 1.4? 
Especially, what if the library you are making has dependencies on some third-party code? For example, JSTL uses a specific version of xalan.jar?

What is the proper way to jar up these libraries so they can be used by a J2EE application?
According to J2EE spec(section 8.2 and 8.4), if you want to make a jar that is used as an optional package then it should be packaged as a .jar file according to the Extension Mechanism Architecture. So the jar file should have manifest file that declares its dependencies.

你可能感兴趣的:(Web,struts,ext,J2SE,ejb)