java中的jar文件

官方英文介绍*******************************************************************************************

Introduction

JAR file is a file format based on the popular ZIP file format and is used for aggregating many files into one. A JAR file is essentially a zip file that contains an optional META-INF directory. A JAR file can be created by the command-line jar tool, or by using the java.util.jar API in the Java platform. There is no restriction on the name of a JAR file, it can be any legal file name on a particular platform.

Modular JAR files

A modular JAR file is a JAR file that has a module descriptor, module-info.class, in the top-level directory (or root) directory. The module descriptor is the binary form of a module declaration. (Note the section on multi-release JAR files further refines the definition of modular JAR files.)

A modular JAR file deployed on the module path, as opposed to the class path, is an explicit module. Dependences and service providers are declared in the module descriptor. If the modular JAR file is deployed on the class path then it behaves as if a non-modular JAR file.

A non-modular JAR file deployed on the module path is an automatic module. If the JAR file has a main attribute Automatic-Module-Name (see Main Attributes) then the attribute's value is the module name, otherwise the module name is derived from the name of the JAR file as specified in ModuleFinder.of(Path...).

Multi-release JAR files

A multi-release JAR file allows for a single JAR file to support multiple major versions of Java platform releases. For example, a multi-release JAR file can depend on both the Java 8 and Java 9 major platform releases, where some class files depend on APIs in Java 8 and other class files depend on APIs in Java 9. This enables library and framework developers to decouple the use of APIs in a specific major version of a Java platform release from the requirement that all their users migrate to that major version. Library and framework developers can gradually migrate to and support new Java features while still supporting the old features.

A multi-release JAR file is identified by the main attribute:

Multi-Release: true

declared in the main section of the JAR Manifest.

Classes and resource files dependent on a major version, 9 or greater, of a Java platform release may be located under a versioned directory instead of under the top-level (or root) directory. The versioned directory is located under the the META-INF directory and is of the form:

META-INF/versions/N

where N is the string representation of the major version number of a Java platform release. Specifically N must conform to the specification:

N: {1-9} {0-9}*

Any versioned directory whose value of N is less than 9 is ignored as is a string representation of N that does not conform to the above specification.

A class file under a versioned directory, of version N say, in a multi-release JAR must have a class file version less than or equal to the class file version associated with Nth major version of a Java platform release. If the class of the class file is public or protected then that class must preside over a class of the same fully qualified name and access modifier whose class file is present under the top-level directory. By logical extension this applies to a class of a class file, if present, under a versioned directory whose version is less than N.

If a multi-release JAR file is deployed on the class path or module path (as an automatic module or an explicit multi-release module) of major version N of a Java platform release runtime, then a class loader loading classes from that JAR file will first search for class files under the Nth versioned directory, then prior versioned directories in descending order (if present), down to a lower major version bound of 9, and finally under the top-level directory.

The public API exported by the classes in a multi-release JAR file must be exactly the same across versions, hence at a minimum why versioned public or protected classes for class files under a versioned directory must preside over classes for class files under the top-level directory. It is difficult and costly to perform extensive API verification checks as such tooling, such as the jar tool, is not required to perform extensive verification and a Java runtime is not required to perform any verification. A future release of this specification may relax the exact same API constraint to support careful evolution.

Resources under the META-INF directory cannot be versioned (such as for service configuration).

A multi-release JAR file can be signed.

Multi-release JAR files are not supported by the boot class loader of a Java runtime. If a multi-release JAR file is appended to the boot class path (with the -Xbootclasspath/a option) then the JAR is treated as if it is an ordinary JAR file.

Modular multi-release JAR files

A modular multi-release JAR file is a multi-release JAR file that has a module descriptor, module-info.class, in the top-level directory (as for a modular JAR file), or directly in a versioned directory.

A public or protected class in a non-exported package (that is not declared as exported in the module descriptor) need not preside over a class of the same fully qualified name and access modifier whose class file is present under the top-level directory.

A module descriptor is generally treated no differently to any other class or resource file. A module descriptor may be present under a versioned area but not present under the top-level directory. This ensures, for example, only Java 8 versioned classes can be present under the top-level directory while Java 9 versioned classes (including, or perhaps only, the module descriptor) can be present under the 9 versioned directory.

Any versioned module descriptor that presides over a lesser versioned module descriptor or that at the top-level, M say, must be identical to M, with two exceptions:

  1. the presiding versioned descriptor can have different non-transitive requires clauses of java.* and jdk.* modules; and
  2. the presiding versioned descriptor can have different uses clauses, even of service types defined outside of java.* and jdk.* modules.

Tooling, such as the jar tool, should perform such verification of versioned module descriptors but a Java runtime is not required to perform any verification.

The META-INF directory

The following files/directories in the META-INF directory are recognized and interpreted by the Java 2 Platform to configure applications, class loaders and services:

  • MANIFEST.MF

The manifest file that is used to define package related data.

  • INDEX.LIST

This file is generated by the new "-i" option of the jar tool, which contains location information for packages defined in an application. It is part of the JarIndex implementation and used by class loaders to speed up their class loading process.

  • x.SF

The signature file for the JAR file. 'x' stands for the base file name.

  • x.DSA

The signature block file associated with the signature file with the same base file name. This file stores the digital signature of the corresponding signature file.

  • services/

This directory stores all the service provider configuration files for JAR files deployed on the class path or JAR files deployed as automatic modules on the module path. See the specification of service provider development for more details.

  • versions/

This directory contains underneath it versioned class and resource files for a multi-release JAR file.

Name-Value pairs and Sections

Before we go to the details of the contents of the individual configuration files, some format convention needs to be defined. In most cases, information contained within the manifest file and signature files is represented as so-called "name: value" pairs inspired by the RFC822 standard. We also call these pairs headers or attributes.

Groups of name-value pairs are known as a "section". Sections are separated from other sections by empty lines.

Binary data of any form is represented as base64. Continuations are required for binary data which causes line length to exceed 72 bytes. Examples of binary data are digests and signatures.

Implementations shall support header values of up to 65535 bytes.

All the specifications in this document use the same grammar in which terminal symbols are shown in fixed width font and non-terminal symbols are shown in italic type face.

Specification:

section: *header +newline
nonempty-section: +header +newline
newline: CR LF | LF | CR (not followed by LF)
header: name : value
name: alphanum *headerchar
value: SPACE *otherchar newline *continuation
continuation: SPACE *otherchar newline
alphanum: {A-Z} | {a-z} | {0-9}
headerchar: alphanum | - | _
otherchar: any UTF-8 character except NUL, CR and LF
  • Note: To prevent mangling of files sent via straight e-mail, no header will start with the four letters "From".

Non-terminal symbols defined in the above specification will be referenced in the following specifications.

JAR Manifest

Overview

A JAR file manifest consists of a main section followed by a list of sections for individual JAR file entries, each separated by a newline. Both the main section and individual sections follow the section syntax specified above. They each have their own specific restrictions and rules.

  • The main section contains security and configuration information about the JAR file itself, as well as the application. It also defines main attributes that apply to every individual manifest entry. No attribute in this section can have its name equal to "Name". This section is terminated by an empty line.

  • The individual sections define various attributes for packages or files contained in this JAR file. Not all files in the JAR file need to be listed in the manifest as entries, but all files which are to be signed must be listed. The manifest file itself must not be listed. Each section must start with an attribute with the name as "Name", and the value must be a relative path to the file, or an absolute URL referencing data outside the archive.

  • If there are multiple individual sections for the same file entry, the attributes in these sections are merged. If a certain attribute have different values in different sections, the last one is recognized.

  • Attributes which are not understood are ignored. Such attributes may include implementation specific information used by applications.

Manifest Specification:

manifest-file: main-section newline *individual-section
main-section: version-info newline *main-attribute
version-info: Manifest-Version : version-number
version-number: digit+{.digit+}*
main-attribute: (any legitimate main attribute) newline
individual-section: Name : value newline *perentry-attribute
perentry-attribute: (any legitimate perentry attribute) newline
newline: CR LF | LF | CR (not followed by LF)
digit: {0-9}

In the above specification, attributes that can appear in the main section are referred to as main attributes, whereas attributes that can appear in individual sections are referred to as per-entry attributes. Certain attributes can appear both in the main section and the individual sections, in which case the per-entry attribute value overrides the main attribute value for the specified entry. The two types of attributes are defined as follows.

Main Attributes

Main attributes are the attributes that are present in the main section of the manifest. They fall into the following different groups:

  • general main attributes
    • Manifest-Version: Defines the manifest file version. The value is a legitimate version number, as described in the above spec.
    • Created-By: Defines the version and the vendor of the java implementation on top of which this manifest file is generated. This attribute is generated by the jar tool.
    • Signature-Version: Defines the signature version of the jar file. The value should be a valid version-number string.
    • Class-Path: The value of this attribute specifies the relative URLs of the libraries that this application needs. URLs are separated by one or more spaces. The application class loader uses the value of this attribute to construct its internal search path. See Class-Path Attribute section for details.
    • Automatic-Module-Name: Defines the module name if this JAR file is deployed as an automatic module on the module path. For further details see the specification of automatic modules.
    • Multi-Release: This attribute defines whether this JAR file is a multi-release JAR file. If the value is "true" , case is ignored, then the JAR file will be processed by the Java runtime and tooling as a multi-release JAR file. Otherwise, if the value is anything other than "true" then this attribute is ignored.
  • attribute defined for stand-alone applications: This attribute is used by stand-alone applications that are bundled into executable jar files which can be invoked by the java runtime directly by running "java -jar x.jar".
    • Main-Class: The value of this attribute is the class name of the main application class which the launcher will load at startup time. The value must not have the .class extension appended to the class name.
    • Launcher-Agent-Class: If this attribute is present then its value is the class name of a java agent that is started before the application main method is invoked. This attribute can be used for cases where a java agent is packaged in the same executable JAR file as the application. The agent class defines a public static method name agentmain in one of the two forms specified in the java.lang.instrumentpackage summary. Additional attributes (such as Can-Retransform-Classes) can be used to indicate capabilities needed by the agent.
  • attributes defined for package versioning and sealing information: The value of these attributes apply to all the packages in the JAR file, but can be overridden by per-entry attributes.
    • Implementation-Title: The value is a string that defines the title of the extension implementation.
    • Implementation-Version: The value is a string that defines the version of the extension implementation.
    • Implementation-Vendor: The value is a string that defines the organization that maintains the extension implementation.
    • Specification-Title: The value is a string that defines the title of the extension specification.
    • Specification-Version: The value is a string that defines the version of the extension specification.
    • Specification-Vendor: The value is a string that defines the organization that maintains the extension specification.
    • Sealed: This attribute defines whether this JAR file is sealed or not. The value can be either "true" or "false", case is ignored. If it is set to "true", then all the packages in the JAR file are defaulted to be sealed, unless they are defined otherwise individually. See also the Package Sealing section.

Per-Entry Attributes

Per-entry attributes apply only to the individual JAR file entry to which the manifest entry is associated with. If the same attribute also appeared in the main section, then the value of the per-entry attribute overwrites the main attribute's value. For example, if JAR file a.jar has the following manifest content:

    Manifest-Version: 1.0
    Created-By: 1.8 (Oracle Inc.)
    Sealed: true
    Name: foo/bar/
    Sealed: false

It means that all the packages archived in a.jar are sealed, except that package foo.bar is not.

The per-entry attributes fall into the following groups:

  • attributes defined for file contents:
    • Content-Type: This attribute can be used to specify the MIME type and subtype of data for a specific file entry in the JAR file. The value should be a string in the form of type/subtype. For example "image/bmp" is an image type with a subtype of bmp (representing bitmap). This would indicate the file entry as an image with the data stored as a bitmap. RFC 1521 and 1522 discuss and define the MIME types definition.
  • attributes defined for package versioning and sealing information: These are the same set of attributes defined above as main attributes that defines the extension package versioning and sealing information. When used as per-entry attributes, these attributes overwrites the main attributes but only apply to the individual file specified by the manifest entry.
  • attribute defined for beans objects:
    • Java-Bean: Defines whether the specific jar file entry is a Java Beans object or not. The value should be either "true" or "false", case is ignored.
  • attributes defined for signing: These attributes are used for signing and verifying purposes. More details here.
    • x-Digest-y: The name of this attribute specifies the name of the digest algorithm used to compute the digest value for the corresponding jar file entry. The value of this attribute stores the actual digest value. The prefix 'x' specifies the algorithm name and the optional suffix 'y' indicates to which language the digest value should be verified against.
    • Magic: This is an optional attribute that can be used by applications to indicate how verifier should compute the digest value contained in the manifest entry. The value of this attribute is a set of comma separated context specific strings. Detailed description is here.

Signed JAR File

Overview

A JAR file can be signed by using the command line jarsigner tool or directly through the java.security API. Every file entry, including non-signature related files in the META-INF directory, will be signed if the JAR file is signed by the jarsigner tool. The signature related files are:

  • META-INF/MANIFEST.MF
  • META-INF/*.SF
  • META-INF/*.DSA
  • META-INF/*.RSA
  • META-INF/SIG-*

Note that if such files are located in META-INF subdirectories, they are not considered signature-related. Case-insensitive versions of these filenames are reserved and will also not be signed.

Subsets of a JAR file can be signed by using the java.security API. A signed JAR file is exactly the same as the original JAR file, except that its manifest is updated and two additional files are added to the META-INFdirectory: a signature file and a signature block file. When jarsigner is not used, the signing program has to construct both the signature file and the signature block file.

For every file entry signed in the signed JAR file, an individual manifest entry is created for it as long as it does not already exist in the manifest. Each manifest entry lists one or more digest attributes and an optional Magic attribute.

Signature File

Each signer is represented by a signature file with extension .SF. The major part of the file is similar to the manifest file. It consists of a main section which includes information supplied by the signer but not specific to any particular jar file entry. In addition to the Signature-Version and Created-By attributes (see Main Attributes), the main section can also include the following security attributes:

  • x-Digest-Manifest-Main-Attributes (where x is the standard name of a java.security.MessageDigest algorithm): The value of this attribute is the digest value of the main attributes of the manifest.
  • x-Digest-Manifest (where x is the standard name of a java.security.MessageDigest algorithm): The value of this attribute is the digest value of the entire manifest.

The main section is followed by a list of individual entries whose names must also be present in the manifest file. Each individual entry must contain at least the digest of its corresponding entry in the manifest file.

Paths or URLs appearing in the manifest file but not in the signature file are not used in the calculation.

Signature Validation

A successful JAR file verification occurs if the signature(s) are valid, and none of the files that were in the JAR file when the signatures were generated have been changed since then. JAR file verification involves the following steps:

  1. Verify the signature over the signature file when the manifest is first parsed. For efficiency, this verification can be remembered. Note that this verification only validates the signature directions themselves, not the actual archive files.

  2. If an x-Digest-Manifest attribute exists in the signature file, verify the value against a digest calculated over the entire manifest. If more than one x-Digest-Manifest attribute exists in the signature file, verify that at least one of them matches the calculated digest value.

  3. If an x-Digest-Manifest attribute does not exist in the signature file or none of the digest values calculated in the previous step match, then a less optimized verification is performed:

    1. If an x-Digest-Manifest-Main-Attributes entry exists in the signature file, verify the value against a digest calculated over the main attributes in the manifest file. If this calculation fails, then JAR file verification fails. This decision can be remembered for efficiency. If an x-Digest-Manifest-Main-Attributes entry does not exist in the signature file, its nonexistence does not affect JAR file verification and the manifest main attributes are not verified.

    2. Verify the digest value in each source file information section in the signature file against a digest value calculated against the corresponding entry in the manifest file. If any of the digest values don't match, then JAR file verification fails.

    One reason the digest value of the manifest file that is stored in the x-Digest-Manifest attribute may not equal the digest value of the current manifest file is that one or more files were added to the JAR file (using the jar tool) after the signature (and thus the signature file) was generated. When the jar tool is used to add files, the manifest file is changed (sections are added to it for the new files), but the signature file is not. A verification is still considered successful if none of the files that were in the JAR file when the signature was generated have been changed since then, which is the case if the digest values in the non-header sections of the signature file equal the digest values of the corresponding sections in the manifest file.

  4. For each entry in the manifest, verify the digest value in the manifest file against a digest calculated over the actual data referenced in the "Name:" attribute, which specifies either a relative file path or URL. If any of the digest values don't match, then JAR file verification fails.

Example manifest file:

    Manifest-Version: 1.0
    Created-By: 1.8.0 (Oracle Inc.)

    Name: common/class1.class
    SHA-256-Digest: (base64 representation of SHA-256 digest)

    Name: common/class2.class
    SHA1-Digest: (base64 representation of SHA1 digest)
    SHA-256-Digest: (base64 representation of SHA-256 digest)

The corresponding signature file would be:

    Signature-Version: 1.0
    SHA-256-Digest-Manifest: (base64 representation of SHA-256 digest)
    SHA-256-Digest-Manifest-Main-Attributes: (base64 representation of SHA-256 digest)

    Name: common/class1.class
    SHA-256-Digest: (base64 representation of SHA-256 digest)

    Name: common/class2.class
    SHA-256-Digest: (base64 representation of SHA-256 digest)

The Magic Attribute

Another requirement to validate the signature on a given manifest entry is that the verifier understand the value or values of the Magic key-pair value in that entry's manifest entry.

The Magic attribute is optional but it is required that a parser understand the value of an entry's Magic key if it is verifying that entry's signature.

The value or values of the Magic attribute are a set of comma-separated context-specific strings. The spaces before and after the commas are ignored. Case is ignored. The exact meaning of the magic attributes is application specific. These values indicate how to compute the hash value contained in the manifest entry, and are therefore crucial to the proper verification of the signature. The keywords may be used for dynamic or embedded content, multiple hashes for multilingual documents, etc.

Here are two examples of the potential use of Magic attribute in the manifest file:

        Name: http://www.example-scripts.com/index#script1
        SHA-256-Digest: (base64 representation of SHA-256 hash)
        Magic: JavaScript, Dynamic

        Name: http://www.example-tourist.com/guide.html
        SHA-256-Digest: (base64 representation of SHA-256 hash)
        SHA-256-Digest-French: (base64 representation of SHA-256 hash)
        SHA-256-Digest-German: (base64 representation of SHA-256 hash)
        Magic: Multilingual

In the first example, these Magic values may indicate that the result of an http query is the script embedded in the document, as opposed to the document itself, and also that the script is generated dynamically. These two pieces of information indicate how to compute the hash value against which to compare the manifest's digest value, thus comparing a valid signature.

In the second example, the Magic value indicates that the document retrieved may have been content-negotiated for a specific language, and that the digest to verify against is dependent on which language the document retrieved is written in.

Digital Signatures

A digital signature is a signed version of the .SF signature file. These are binary files not intended to be interpreted by humans.

Digital signature files have the same filenames as the .SF files but different extensions. The extension varies depending on the type of digital signature.

  • .RSA (PKCS7 signature, SHA-256 + RSA)
  • .DSA (PKCS7 signature, DSA)

Digital signature files for signature algorithms not listed above must reside in the META-INF directory and have the prefix "SIG-". The corresonding signature file (.SF file) must also have the same prefix.

For those formats that do not support external signed data, the file shall consist of a signed copy of the .SF file. Thus some data may be duplicated and a verifier should compare the two files.

Formats that support external data either reference the .SF file, or perform calculations on it with implicit reference.

Each .SF file may have multiple digital signatures, but those signatures should be generated by the same legal entity.

File name extensions may be 1 to 3 alphanum characters. Unrecognized extensions are ignored.

Notes on Manifest and Signature Files

Following is a list of additional restrictions and rules that apply to manifest and signature files.

  • Before parsing:
    • If the last character of the file is an EOF character (code 26), the EOF is treated as whitespace. Two newlines are appended (one for editors that don't put a newline at the end of the last line, and one so that the grammar doesn't have to special-case the last entry, which may not have a blank line after it).
  • Attributes:
    • In all cases for all sections, attributes which are not understood are ignored.
    • Attribute names are case insensitive. Programs which generate manifest and signature files should use the cases shown in this specification however.
    • Attribute names cannot be repeated within a section.
  • Versions:
    • Manifest-Version and Signature-Version must be first, and in exactly that case (so that they can be recognized easily as magic strings). Other than that, the order of attributes within a main section is not significant.
  • Ordering:
    • The order of individual manifest entries is not significant.
    • The order of individual signature entries is not significant, except that the digests that get signed are in that order.
  • Line length:
    • No line may be longer than 72 bytes (not characters), in its UTF8-encoded form. If a value would make the initial line longer than this, it should be continued on extra lines (each starting with a single SPACE).
  • Errors:
    • If a file cannot be parsed according to this spec, a warning should be output, and none of the signatures should be trusted.
  • Limitations:
    • Because header names cannot be continued, the maximum length of a header name is 70 bytes (there must be a colon and a SPACE after the name).
    • NUL, CR, and LF can't be embedded in header values, and NUL, CR, LF and ":" can't be embedded in header names.
    • Implementations should support 65535-byte (not character) header values, and 65535 headers per file. They might run out of memory, but there should not be hard-coded limits below these values.
  • Signers:
    • It is technically possible that different entities may use different signing algorithms to share a single signature file. This violates the standard, and the extra signature may be ignored.
  • Algorithms:
    • No digest algorithm or signature algorithm is mandated by this standard. However, at least one of SHA-256 and SHA1 digest algorithm must be supported.

JAR Index

Overview

Since 1.3, JarIndex is introduced to optimize the class searching process of class loaders for network applications, especially applets. Originally, an applet class loader uses a simple linear search algorithm to search each element on its internal search path, which is constructed from the "ARCHIVE" tag or the "Class-Path" main attribute. The class loader downloads and opens each element in its search path, until the class or resource is found. If the class loader tries to find a nonexistent resource, then all the jar files within the application or applet will have to be downloaded. For large network applications and applets this could result in slow startup, sluggish response and wasted network bandwidth. The JarIndex mechanism collects the contents of all the jar files defined in an applet and stores the information in an index file in the first jar file on the applet's class path. After the first jar file is downloaded, the applet class loader will use the collected content information for efficient downloading of jar files.

The existing jar tool is enhanced to be able to examine a list of jar files and generate directory information as to which classes and resources reside in which jar file. This directory information is stored in a simple text file named INDEX.LIST in the META-INF directory of the root jar file. When the classloader loads the root jar file, it reads the INDEX.LIST file and uses it to construct a hash table of mappings from file and package names to lists of jar file names. In order to find a class or a resource, the class loader queries the hashtable to find the proper jar file and then downloads it if necessary.

Once the class loader finds a INDEX.LIST file in a particular jar file, it always trusts the information listed in it. If a mapping is found for a particular class, but the class loader fails to find it by following the link, an unspecified Error or RuntimeException is thrown. When this occurs, the application developer should rerun the jar tool on the extension to get the right information into the index file.

To prevent adding too much space overhead to the application and to speed up the construction of the in-memory hash table, the INDEX.LIST file is kept as small as possible. For classes with non-null package names, mappings are recorded at the package level. Normally one package name is mapped to one jar file, but if a particular package spans more than one jar file, then the mapped value of this package will be a list of jar files. For resource files with non-empty directory prefixes, mappings are also recorded at the directory level. Only for classes with null package name, and resource files which reside in the root directory, will the mapping be recorded at the individual file level.

Index File Specification

The INDEX.LIST file contains one or more sections each separated by a single blank line. Each section defines the content of a particular jar file, with a header defining the jar file path name, followed by a list of package or file names, one per line. All the jar file paths are relative to the code base of the root jar file. These path names are resolved in the same way as the current extension mechanism does for bundled extensions.

The UTF-8 encoding is used to support non ASCII characters in file or package names in the index file.

Specification

index file: version-info blankline section*
version-info: JarIndex-Version: version-number
version-number: digit+{.digit+}*
section: body blankline
body: header name*
header: char+.jar newline
name: char+ newline
char: any valid Unicode character except NULL, CR andLF
blankline: newline newline
newline: CR LF | LF | CR (not followed by LF)
digit: {0-9}

The INDEX.LIST file is generated by running jar -i. See the jar man page for more details.

Backward Compatibility

The new class loading scheme is totally backward compatible with applications developed on top of the current extension mechanism. When the class loader loads the first jar file and an INDEX.LIST file is found in the META-INF directory, it would construct the index hash table and use the new loading scheme for the extension. Otherwise, the class loader will simply use the original linear search algorithm.

Class-Path Attribute

The manifest for an application can specify one or more relative URLs referring to the JAR files and directories for other libraries that it needs. These relative URLs will be treated relative to the code base that the containing application was loaded from.

An application (or, more generally, JAR file) specifies the relative URLs of the libraries that it needs via the manifest attribute Class-Path. This attribute lists the URLs to search for implementations of other libraries if they cannot be found on the host Java Virtual Machine. These relative URLs may include JAR files and directories for any libraries or resources needed by the application. Relative URLs not ending with '/' are assumed to refer to JAR files. For example,

Class-Path: servlet.jar infobus.jar acme/beans.jar images/

At most one Class-Path header may be specified in a JAR file's manifest..

Currently, the URLs must be relative to the code base of the JAR file for security reasons. Thus, remote optional packages will originate from the same code base as the application.

Each relative URL is resolved against the code base that the containing application or library was loaded from. If the resulting URL is invalid or refers to a resource that cannot be found then it is ignored.

The resulting URLs are used to extend the class path for the application, applet, or servlet by inserting the URLs in the class path immediately following the URL of the containing JAR file. Any duplicate URLs are omitted. For example, given the following class path:

a.jar b.jar

If b.jar contained the following Class-Path manifest attribute:

Class-Path: x.jar a.jar

Then the resulting application class path would be the following:

a.jar b.jar x.jar

Of course, if x.jar had dependencies of its own then these would be added according to the same rules and so on for each subsequent URL. In the actual implementation, JAR file dependencies are processed lazily so that the JAR files are not actually opened until needed.

Package Sealing

JAR files and packages can be optionally sealed, so that an package can enforce consistency within a version.

A package sealed within a JAR specifies that all classes defined in that package must originate from the same JAR. Otherwise, a SecurityException is thrown.

A sealed JAR specifies that all packages defined by that JAR are sealed unless overridden specifically for a package.

A sealed package is specified via the manifest attribute, Sealed, whose value is true or false (case irrelevant). For example,

    Name: javax/servlet/internal/
    Sealed: true

specifies that the javax.servlet.internal package is sealed, and that all classes in that package must be loaded from the same JAR file.

If this attribute is missing, the package sealing attribute is that of the containing JAR file.

A sealed JAR is specified via the same manifest header, Sealed, with the value again of either true or false. For example,

    Sealed: true

specifies that all packages in this archive are sealed unless explicitly overridden for a particular package with the Sealed attribute in a manifest entry.

If this attribute is missing, the JAR file is assumed to not be sealed, for backwards compatibility. The system then defaults to examining package headers for sealing information.

Package sealing is also important for security, because it restricts access to package-protected members to only those classes defined in the package that originated from the same JAR file.

The unnamed package is not sealable, so classes that are to be sealed must be placed in their own packages.

官方中文介绍*******************************************************************************************

介绍

JAR文件是基于流行的ZIP文件格式的文件格式,用于将许多文件聚合为一个。JAR文件本质上是一个包含可选META-INF目录的zip文件。JAR文件可以通过命令行jar工具创建,也可以使用java.util.jarJava平台中的API创建。对JAR文件的名称没有限制,它可以是特定平台上的任何合法文件名。

模块化JAR文件

模块化JAR文件是module-info.class在顶级目录(或根目录)目录中具有模块描述符的JAR文件。模块描述符是模块声明的二进制形式。(注意有关多版本JAR文件的部分进一步细化了模块化JAR文件的定义。)

部署在模块路径上的模块化JAR文件(与类路径相对)是一个显式模块。依赖项和服务提供程序在模块描述符中声明。如果模块化JAR文件部署在类路径上,那么它的行为就像非模块化JAR文件一样。

部署在模块路径上的非模块化JAR文件是自动模块。如果JAR文件具有主属性Automatic-Module-Name(请参阅主要属性),则属性的值是模块名称,否则模块名称是从中指定的JAR文件的名称派生的ModuleFinder.of(Path...)

多版本JAR文件

多版本JAR文件允许单个JAR文件支持多个主要版本的Java平台版本。例如,多版本JAR文件可以依赖于Java 8和Java 9主要平台版本,其中一些类文件依赖于Java 8中的API,而其他类文件依赖于Java 9中的API。这使库和框架开发人员成为可能将Java平台版本的特定主要版本中的API的使用与其所有用户迁移到该主要版本的要求分离。库和框架开发人员可以逐步迁移并支持新的Java功能,同时仍支持旧功能。

主要属性标识多版本JAR文件:

Multi-Release: true

JAR清单的主要部分宣布。

依赖于Java平台版本的主要版本(9或更高版本)的类和资源文件可以位于版本化目录下,而不是位于顶级(或根目录)目录下。版本化目录位于META-INF目录下,格式如下:

META-INF/versions/N

其中N是Java平台发行版主要版本号的字符串表示形式。具体N必须符合规范:

N: {1-9} {0-9}*

任何版本化的目录,其值N小于,将9被忽略,因为它的字符串表示N不符合上述规范。

版本化目录下的类文件(N例如,在多版本JAR中)必须具有小于或等于与NJava平台版本的主要版本相关联的类文件版本的类文件版本。如果类文件的类是公共的或受保护的,那么该类必须主持一个相同的完全限定名称和访问修饰符的类,其类文件存在于顶级目录下。通过逻辑扩展,这适用于类文件的类(如果存在),在版本小于的版本化目录下N

如果在Java平台发布运行时的主要版本的类路径或模块路径(作为自动模块或显式多发布模块)上部署多版本JAR文件N,则从该JAR文件加载类的类加载器将首先搜索N版本化目录下的类文件,然后按降序排列先前版本的目录(如果存在),下载到较低的主要版本9,最后搜索顶级目录。

多版本JAR文件中的类导出的公共API在不同版本中必须完全相同,因此至少为什么版本化目录下的类文件的版本化公共类或受保护类必须主持类顶层下的类文件的类 -级别目录。执行广泛的API验证检查既困难又昂贵,因为这样的工具(例如jar工具)不需要执行大量验证,并且不需要Java运行时来执行任何验证。此规范的未来版本可能会放宽完全相同的API约束以支持细致的演变。

META-INF目录下的资源无法进行版本控制(例如用于服务配置)。

可以签署多版本JAR文件。

Java运行时的引导类加载器不支持多版本JAR文件。如果将多版本JAR文件附加到引导类路径(使用该-Xbootclasspath/a选项),则将JAR视为普通JAR文件。

模块化多版本JAR文件

模块化多版本JAR文件是一个多版本JAR文件,它具有模块描述符module-info.class,位于顶级目录(对于模块化 JAR文件),或直接位于版本化目录中。

非导出包中的公共或受保护类(未声明为在模块描述符中导出)不需要主持一个相同的完全限定名称和访问修饰符的类,其类文件存在于顶级目录下。

模块描述符通常与任何其他类或资源文件的处理方式没有区别。模块描述符可以存在于版本化区域下但不存在于顶级目录下。例如,这确保了只有Java 8版本化的类可以存在于顶级目录下,而Java 9版本化的类(包括或者可能只是模块描述符)可以存在于9版本化目录下。

任何版本化的模块描述符,主持较小的版本化模块描述符,或者在顶层,M例如,必须相同M,但有两个例外:

  1. 主持版本化描述符可以具有不同的transitive requires子句java.*jdk.*模块; 和
  2. 主持版本描述符可以具有不同的uses条款,甚至之外定义服务类型java.*jdk.*模块。

工具(例如jar工具)应该对版本化模块描述符执行此类验证,但不需要Java运行时来执行任何验证。

META-INF目录

Java 2平台可识别和解释META-INF目录中的以下文件/目录,以配置应用程序,类加载器和服务:

  • MANIFEST.MF

清单文件,用于定义与包相关的数据。

  • INDEX.LIST

此文件由-i"jar工具的新选项生成,该选项包含应用程序中定义的包的位置信息。它是JarIndex实现的一部分,并由类加载器用于加速其类加载过程。

  • x.SF

JAR文件的签名文件。'x'代表基本文件名。

  • x.DSA

与签名文件关联的签名块文件具有相同的基本文件名。该文件存储相应签名文件的数字签名。

  • services/

此目录存储部署在类路径上的JAR文件的所有服务提供者配置文件或部署为模块路径上的自动模块的JAR文件。有关更多详细信息,请参阅服务提供商开发规范。

  • versions/

该目录下面包含多版本 JAR文件的版本化类和资源文件。

名称 - 值对和部分

在我们详细介绍各个配置文件的内容之前,需要定义一些格式约定。在大多数情况下,清单文件和签名文件中包含的信息表示为受RFC822标准启发的所谓“名称:值”对。我们还称这些对标题或属性。

名称 - 值对的组称为“部分”。截面用空行与其他部分分开。

任何形式的二进制数据表示为base64。二进制数据需要连续,这导致行长度超过72个字节。二进制数据的示例是摘要和签名。

实现应支持最多65535字节的标头值。

本文档中的所有规范使用相同的语法,其中终端符号以固定宽度字体显示,而非终端符号以斜体字体显示。

规格:

部分: *标题+换行符
非空段: +标题+换行符
新队: CR LF | LF | CR没有跟着 LF
标题: 名称 : 
名称: alphanum * headerchar
值: SPACE * otherchar换行符*延续
延续: SPACE * otherchar换行符
alphanum: A-Z} | { a-z} | { 0-9}
headerchar: alphanum | -|_
otherchar:  之外的任何UTF-8字符NUL, CR LF
  • 注意:为防止通过直接电子邮件发送文件,不会以四个字母“From”开头。

上述规范中定义的非终端符号将在以下规范中引用。

JAR清单

概观

JAR文件清单包含一个主要部分,后跟各个JAR文件条目的部分列表,每个部分由换行符分隔。主要部分和各个部分都遵循上面指定的部分语法。他们每个人都有自己的特定限制和规则。

  • 主要部分包含有关JAR文件本身以及应用程序的安全性和配置信息。它还定义了适用于每个单独清单条目的主要属性。此部分中的任何属性都不能使其名称等于“ Name”。此部分以空行终止。

  • 各个部分定义此JAR文件中包含的包或文件的各种属性。并非JAR文件中的所有文件都需要作为条目列在清单中,但必须列出要签名的所有文件。不得列出清单文件本身。每个部分必须以名称为“ Name” 的属性开头,并且值必须是文件的相对路径,或者是引用存档外部数据的绝对URL。

  • 如果同一文件条目有多个单独的部分,则合并这些部分中的属性。如果某个属性在不同的部分中具有不同的值,则会识别最后一个属性。

  • 忽略不理解的属性。这些属性可以包括应用程序使用的实现特定信息。

清单规格:

清单文件: 主要部分换行*个别部分
主部: version-info newline * main-attribute
版本信息: Manifest-Version : 版本号
版本号: 数字+ { .数字+} *
主要属性: (任何合法的主要属性)换行符
个别部分: Name :  换行* perentry-attribute
perentry属性: (任何合法的perentry属性)换行符
新队: CR LF | LF | CR没有跟着 LF
数字: {0-9}

在上面的规范中,可以出现在主要部分中的属性被称为主要属性,而可以出现在各个部分中的属性被称为每个条目属性。某些属性可以出现在主要部分和各个部分中,在这种情况下,每个条目属性值将覆盖指定条目的主要属性值。两种类型的属性定义如下。

主要属性

主要属性是清单主要部分中存在的属性。他们属于以下不同的群体:

  • 一般主要属性
    • 清单 - 版本:定义清单文件版本。该值是合法的版本号,如上面的规范中所述。
    • Created-By:定义生成此清单文件的java实现的版本和供应商。该属性由该jar工具生成。
    • 签名版本:定义jar文件的签名版本。该值应为有效的版本号字符串。
    • Class-Path:此属性的值指定此应用程序所需的库的相对URL。URL由一个或多个空格分隔。应用程序类加载器使用此属性的值来构造其内部搜索路径。有关详细信息,请参阅类路径属性部分。
    • Automatic-Module-Name:如果将此JAR文件部署为模块路径上的自动模块,则定义模块名称。有关详细信息,请参阅规范automatic modules
    • Multi-Release:此属性定义此JAR文件是否为多版本 JAR文件。如果值为“true”,则忽略大小写,然后Java运行时和工具将JAR文件作为多版本JAR文件进行处理。否则,如果该值不是“true”,则忽略此属性。
  • 为独立应用程序定义的属性:此属性由捆绑到可执行jar文件的独立应用程序使用,可由java运行时直接通过运行“ java -jar x.jar” 来调用。
    • Main-Class:此属性的值是启动时启动程序将加载的主应用程序类的类名。该值不能.class扩展名附加到类名。
    • Launcher-Agent-Class:如果存在此属性,则其值是在调用应用程序main方法之前启动的java代理的类名。此属性可用于将java代理程序打包在与应用程序相同的可执行JAR文件中的情况。agent类agentmainjava.lang.instrument包摘要中指定的两种形式之一定义公共静态方法名称。其他属性(例如Can-Retransform-Classes)可用于指示代理所需的功能。
  • 包版本控制和密封信息定义的属性:这些属性的值适用于JAR文件中的所有包,但可以由每个条目属性覆盖。
    • Implementation-Title:值是一个字符串,用于定义扩展实现的标题。
    • Implementation-Version:该值是一个字符串,用于定义扩展实现的版本。
    • Implementation-Vendor:该值是一个字符串,用于定义维护扩展实现的组织。
    • Specification-Title:该值是一个字符串,用于定义扩展规范的标题。
    • Specification-Version:该值是一个字符串,用于定义扩展规范的版本。
    • 规范 - 供应商:该值是一个字符串,用于定义维护扩展规范的组织。
    • 密封:此属性定义此JAR文件是否已密封。值可以是“true”或“false”,大小写将被忽略。如果将其设置为“true”,则JAR文件中的所有包都将被默认为密封,除非它们是单独定义的。另请参阅包装密封部分。

每个条目属性

每个条目属性仅适用于与清单条目关联的单个JAR文件条目。如果主要部分中也出现相同的属性,则per-entry属性的值将覆盖主要属性的值。例如,如果JAR文件a.jar具有以下清单内容:

    Manifest-Version: 1.0
    Created-By: 1.8 (Oracle Inc.)
    Sealed: true
    Name: foo/bar/
    Sealed: false

这意味着在a.jar中存档的所有包都是密封的,除了包foo.bar不是。

每个条目属性分为以下几组:

  • 为文件内容定义的属性:
    • Content-Type:此属性可用于为JAR文件中的特定文件条目指定MIME类型和数据子类型。该值应为type / subtype形式的字符串例如,“image / bmp”是具有bmp子类型(表示位图)的图像类型。这将指示文件条目作为图像,其中数据存储为位图。RFC 15211522讨论并定义了MIME类型定义。
  • 为包版本控制和密封信息定义的属性:这些属性是上面定义的相同属性集,用于定义扩展包版本控制和密封信息的主要属性。当用作每个条目属性时,这些属性会覆盖主要属性,但仅适用于清单条目指定的单个文件。
  • 为bean对象定义的属性:
    • Java-Bean:定义特定的jar文件条目是否是Java Beans对象。该值应为“true”或“false”,大小写将被忽略。
  • 为签名定义的属性:这些属性用于签名和验证目的。更多细节在这里。
    • x-Digest-y:此属性的名称指定用于计算相应jar文件条目的摘要值的摘要算法的名称。此属性的值存储实际摘要值。前缀“x”指定算法名称,可选后缀“y”指示应该针对哪种语言验证摘要值。
    • Magic:这是一个可选属性,应用程序可以使用它来指示验证者应如何计算清单条目中包含的摘要值。此属性的值是一组逗号分隔的上下文特定字符串。详细说明如下。

签名的JAR文件

概观

可以使用命令行jarsigner工具或直接通过java.securityAPI 对JAR文件进行签名。META-INF如果JAR文件由jarsigner工具签名,则将对每个文件条目(包括目录中的非签名相关文件)进行签名。签名相关文件是:

  • META-INF/MANIFEST.MF
  • META-INF/*.SF
  • META-INF/*.DSA
  • META-INF/*.RSA
  • META-INF/SIG-*

请注意,如果此类文件位于META-INF子目录中,则不会将其视为与签名相关。这些文件名的不区分大小写的版本是保留的,也不会签名。

可以使用java.securityAPI 对JAR文件的子集进行签名。签名的JAR文件与原始JAR文件完全相同,只是更新其清单并将另外两个文件添加到META-INF目录中:签名文件和签名块文件。当不使用jarsigner时,签名程序必须构造签名文件和签名块文件。

对于在签名的JAR文件中签名的每个文件条目,只要清单中不存在单个清单条目,就会为其创建单独的清单条目。每个清单条目都列出一个或多个摘要属性和可选的Magic属性

签名文件

每个签名者由具有扩展名的签名文件表示.SF。该文件的主要部分类似于清单文件。它由一个主要部分组成,其中包括签名者提供的信息,但不是特定于任何特定的jar文件条目。除了Signature-VersionCreated-By属性(请参阅主要属性)之外,主要部分还可以包括以下安全属性:

  • x-Digest-Manifest-Main-Attributes(其中x是java.security.MessageDigest算法的标准名称):此属性的值是清单主要属性的摘要值。
  • x-Digest-Manifest(其中x是java.security.MessageDigest算法的标准名称):此属性的值是整个清单的摘要值。

主要部分后面是单个条目的列表,其名称也必须出现在清单文件中。每个单独的条目必须至少包含清单文件中其相应条目的摘要。

出现在清单文件中但未出现在签名文件中的路径或URL不会用于计算。

签名验证

如果签名有效,则会发生成功的JAR文件验证,从那时起,生成签名时JAR文件中的所有文件都没有更改。JAR文件验证涉及以下步骤:

  1. 首次解析清单时,验证签名文件上的签名。为了提高效率,可以记住此验证。请注意,此验证仅验证签名方向本身,而不验证实际的归档文件。

  2. 如果x-Digest-Manifest签名文件中存在属性,请针对在整个清单上计算的摘要验证该值。如果x-Digest-Manifest签名文件中存在多个属性,请验证其中至少有一个属性与计算的摘要值匹配。

  3. 如果x-Digest-Manifest签名文件中不存在属性,或者上一步骤中计算的摘要值都不匹配,则执行不太优化的验证:

    1. 如果x-Digest-Manifest-Main-Attributes签名文件中存在条目,请根据清单文件中主要属性计算的摘要验证该值。如果此计算失败,则JAR文件验证失败。可以记住这个决定的效率。如果x-Digest-Manifest-Main-Attributes签名文件中不存在条目,则其不存在不会影响JAR文件验证,并且不会验证清单主要属性。

    2. 根据清单文件中相应条目计算的摘要值,验证签名文件中每个源文件信息部分中的摘要值。如果任何摘要值不匹配,则JAR文件验证失败。

    存储在x-Digest-Manifest属性中的清单文件的摘要值可能不等于当前清单文件的摘要值的一个原因是签名后将一个或多个文件添加到JAR文件(使用jar工具)(因此签名文件)已生成。使用jar工具添加文件时,会更改清单文件(为新文件添加部分),但签名文件不会。如果从那时起生成签名时JAR文件中没有任何文件被更改,则验证仍然被认为是成功的,如果签名文件的非标题部分中的摘要值等于摘要值,则情况就是这种情况清单文件中相应部分的内容。

  4. 对于清单中的每个条目,请根据“Name:”属性中引用的实际数据计算摘要,验证清单文件中的摘要值,该属性指定相对文件路径或URL。如果任何摘要值不匹配,则JAR文件验证失败。

示例清单文件:

    Manifest-Version: 1.0
    Created-By: 1.8.0 (Oracle Inc.)

    Name: common/class1.class
    SHA-256-Digest: (base64 representation of SHA-256 digest)

    Name: common/class2.class
    SHA1-Digest: (base64 representation of SHA1 digest)
    SHA-256-Digest: (base64 representation of SHA-256 digest)

相应的签名文件将是:

    Signature-Version: 1.0
    SHA-256-Digest-Manifest: (base64 representation of SHA-256 digest)
    SHA-256-Digest-Manifest-Main-Attributes: (base64 representation of SHA-256 digest)

    Name: common/class1.class
    SHA-256-Digest: (base64 representation of SHA-256 digest)

    Name: common/class2.class
    SHA-256-Digest: (base64 representation of SHA-256 digest)

魔术属性

验证给定清单条目上的签名的另一个要求是验证者理解该条目的清单条目中的Magic密钥对值的值。

Magic属性是可选的,但要求解析器在验证条目的签名时才能理解条目的Magic密钥的值。

Magic属性的值是一组以逗号分隔的特定于上下文的字符串。逗号前后的空格将被忽略。案例被忽略。魔术属性的确切含义是特定于应用程序的。这些值指示如何计算清单条目中包含的哈希值,因此对于正确验证签名至关重要。关键字可用于动态或嵌入内容,多语言文档的多个哈希等。

以下是清单文件中可能使用Magic属性的两个示例:

        Name: http://www.example-scripts.com/index#script1
        SHA-256-Digest: (base64 representation of SHA-256 hash)
        Magic: JavaScript, Dynamic

        Name: http://www.example-tourist.com/guide.html
        SHA-256-Digest: (base64 representation of SHA-256 hash)
        SHA-256-Digest-French: (base64 representation of SHA-256 hash)
        SHA-256-Digest-German: (base64 representation of SHA-256 hash)
        Magic: Multilingual

在第一个示例中,这些Magic值可能表示http查询的结果是嵌入在文档中的脚本,而不是文档本身,以及脚本是动态生成的。这两条信息指示如何计算用于比较清单的摘要值的哈希值,从而比较有效签名。

在第二个示例中,Magic值表示检索到的文档可能已针对特定语言进行内容协商,并且要验证的摘要取决于所检索文档所写的语言。

数字签名

数字签名是.SF签名文件的签名版本。这些是不打算由人类解释的二进制文件。

数字签名文件与.SF文件具有相同的文件名,但扩展名不同。扩展名根据数字签名的类型而有所不同。

  • .RSA (PKCS7签名,SHA-256 + RSA)
  • .DSA (PKCS7签名,DSA)

上面未列出的签名算法的数字签名文件必须位于META-INF目录中,并带有前缀“ SIG-”。相应的签名文件(.SF文件)也必须具有相同的前缀。

对于那些不支持外部签名数据的格式,该文件应包含该文件的签名副本.SF。因此,一些数据可能被复制,验证者应该比较这两个文件。

支持外部数据的格式可以引用该.SF文件,也可以使用隐式引用对其执行计算。

每个.SF文件可能有多个数字签名,但这些签名应由同一法人实体生成。

文件扩展名可以是1到3 个字母数字字符。无法识别的扩展名将被忽略。

有关清单和签名文件的说明

以下是适用于清单和签名文件的其他限制和规则的列表。

  • 在解析之前:
    • 如果文件的最后一个字符是EOF字符(代码26),则将EOF视为空格。附加两个换行符(一个用于不在最后一行末尾添加换行符的编辑器,另一个用于语法不必具有特殊情况的最后一个条目,其后可能没有空行)。
  • 属性:
    • 在所有部分的所有情况下,忽略不理解的属性。
    • 属性名称不区分大小写。生成清单和签名文件的程序应该使用本规范中显示的情况。
    • 属性名称不能在节中重复。
  • 版本:
    • 清单版本和签名版本必须是第一个,并且在这种情况下(因此它们可以很容易地被识别为魔术字符串)。除此之外,主要部分中的属性顺序并不重要。
  • 排序:
    • 单个清单条目的顺序并不重要。
    • 单个签名条目的顺序并不重要,除了获得签名的摘要按此顺序排列。
  • 线长:
    • 任何行都不能长于72字节(不是字符),采用UTF8编码形式。如果某个值使初始行长于此值,则应在额外行上继续(每个行以单个SPACE开头)。
  • 错误:
    • 如果无法根据此规范解析文件,则应输出警告,并且不应信任任何签名。
  • 限制:
    • 由于标题名称无法继续,标题名称的最大长度为70个字节(名称后必须有冒号和SPACE)。
    • NUL,CR和LF不能嵌入标题值中,并且NUL,CR,LF和“:”不能嵌入标题名称中。
    • 实现应支持65535字节(非字符)标头值,每个文件65535标头。它们可能会耗尽内存,但不应低于这些值的硬编码限制。
  • 签名者:
    • 技术上可能的是,不同的实体可以使用不同的签名算法来共享单个签名文件。这违反了标准,可能会忽略额外的签名。
  • 算法:
    • 本标准未强制要求摘要算法或签名算法。但是,必须至少支持SHA-256和SHA1摘要算法之一。

JAR指数

概观

从1.3开始,引入了JarIndex来优化类加载器的类搜索过程,用于网络应用程序,尤其是applet。最初,applet类加载器使用简单的线性搜索算法来搜索其内部搜索路径上的每个元素,该搜索路径是从“ARCHIVE”标记或“Class-Path”主要属性构造的。类加载器下载并打开其搜索路径中的每个元素,直到找到类或资源。如果类加载器试图找到不存在的资源,则必须下载应用程序或applet中的所有jar文件。对于大型网络应用程序和applet,这可能导致启动缓慢,响应迟缓和网络带宽浪费。JarIndex机制收集applet中定义的所有jar文件的内容,并将信息存储在applet类路径上第一个jar文件的索引文件中。下载第一个jar文件后,applet类加载器将使用收集的内容信息有效下载jar文件。

现有jar工具已得到增强,能够检查jar文件列表并生成有关哪些类和资源驻留在哪个jar文件中的目录信息。此目录信息存储在根jar文件INDEX.LISTMETA-INF目录中命名的简单文本文件中。当类加载器加载根jar文件时,它会读取INDEX.LIST文件并使用它来构造从文件和包名到jar文件名列表的映射哈希表。为了查找类或资源,类加载器查询哈希表以查找正确的jar文件,然后在必要时下载它。

一旦类加载器INDEX.LIST在特定的jar文件中找到文件,它就始终信任其中列出的信息。如果找到特定类的映射,但类加载器无法通过链接找到它,则抛出未指定的Error或RuntimeException。发生这种情况时,应用程序开发人员应jar在扩展上重新运行该工具,以便将正确的信息输入索引文件。

为了防止向应用程序添加太多空间开销并加快内存中哈希表的构造,INDEX.LIST文件保持尽可能小。对于具有非null包名称的类,将在包级别记录映射。通常,一个包名称映射到一个jar文件,但如果特定包跨越多个jar文件,则此包的映射值将是jar文件的列表。对于具有非空目录前缀的资源文件,映射也会记录在目录级别。仅对于具有空包名称的类以及驻留在根目录中的资源文件,将在单个文件级别记录映射。

索引文件规范

INDEX.LIST文件包含一个或多个部分,每个部分由一个空行分隔。每个部分定义一个特定jar文件的内容,其中一个头定义了jar文件的路径名,后面是一个包或文件名列表,每行一个。所有jar文件路径都相对于根jar文件的代码库。这些路径名的解析方式与当前扩展机制对捆绑扩展的解析方式相同。

UTF-8编码用于支持索引文件中文件或包名称中的非ASCII字符。

规格

索引文件: 版本信息空白部分*
版本信息: JarIndex-Version: 版本号
版本号: 数字+ {位数字+} *
部分: 身体空白
身体: 标题名称*
标题: char + .jar 换行符
名称: char +换行符
焦炭:  之外的任何有效Unicode字符NULL, CR LF
空行: 换行换行符
新队: CR LF | LF | CR没有跟着 LF
数字: 0-9}

INDEX.LIST文件是通过运行生成jar -i.请参阅jar手册页以获取更多详细信息。

向后兼容性

新的类加载方案完全向后兼容在当前扩展机制之上开发的应用程序。当类加载器加载第一个jar文件并INDEX.LISTMETA-INF目录中找到一个文件时,它将构造索引哈希表并使用新的加载方案进行扩展。否则,类加载器将简单地使用原始线性搜索算法。

类路径属性

应用程序的清单可以指定一个或多个相对URL,引用它所需的其他库的JAR文件和目录。这些相对URL将相对于加载包含应用程序的代码库进行处理。

应用程序(或更一般地说,JAR文件)通过manifest属性指定所需库的相对URL Class-Path。如果在主机Java虚拟机上找不到其他库的实现,则此属性将列出用于搜索其他库的实现的URL。这些相对URL可以包括应用程序所需的任何库或资源的JAR文件和目录。假设不以'/'结尾的相对URL引用JAR文件。例如,

Class-Path: servlet.jar infobus.jar acme/beans.jar images/

最多Class-Path可以在JAR文件的清单中指定一个标头。

目前,出于安全原因,URL必须对于JAR文件的代码库。因此,远程可选包将源自与应用程序相同的代码库。

每个相对URL都是根据加载包含的应用程序或库的代码库来解析的。如果生成的URL无效或引用了无法找到的资源,则会忽略该URL。

生成的URL用于通过在包含JAR文件的URL之后的类路径中插入URL来扩展应用程序,applet或servlet的类路径。省略任何重复的URL。例如,给定以下类路径:

a.jar b.jar

如果b.jar包含以下Class-Path清单属性:

Class-Path: x.jar a.jar

然后生成的应用程序类路径如下:

a.jar b.jar x.jar

当然,如果x.jar有自己的依赖关系,那么这些将根据相同的规则添加,依此类推每个后续URL。在实际实现中,懒惰地处理JAR文件依赖性,以便在需要之前不实际打开JAR文件。

包装密封

可以选择密封 JAR文件和包,以便包可以在版本中强制实现一致性。

密封在JAR中的包指定该包中定义的所有类必须来自同一个JAR。否则,SecurityException抛出一个。

密封的JAR指定该JAR定义的所有包都是密封的,除非专门针对包重写。

密封包是通过manifest属性指定的Sealed,其值为truefalse(不相关)。例如,

    Name: javax/servlet/internal/
    Sealed: true

指定javax.servlet.internal包是密封的,并且必须从同一个JAR文件加载该包中的所有类。

如果缺少此属性,则包密封属性是包含JAR文件的属性。

密封的JAR通过相同的清单头指定Sealed,其值再次为truefalse。例如,

    Sealed: true

指定此归档中的所有包都是密封的,除非显式覆盖Sealed具有清单条目中属性的特定包。

如果缺少此属性,则假定JAR文件未被密封,以实现向后兼容性。然后,系统默认检查包头是否有密封信息。

程序包密封对于安全性也很重要,因为它将对受程序包保护的成员的访问限制为仅在源自同一JAR文件的程序包中定义的那些类。

未命名的包不可密封,因此要密封的类必须放在它们自己的包中。

猜你喜欢

转载自blog.csdn.net/FYSGXFZ/article/details/83057283