JarURLConnection类通过JAR协议建立了一个访问 jar包URL的连接,可以访问这个jar包或者这个包里的某个文件。
jar URL的形式如下:jar:{archive-url}!/{entry},其中!/是一个分隔符。
示例:
访问http服务器上的Jar包文件: jar:http://www.jcg.com/bar/baz.jar!/
访问http服务器上Jar包内的文件:jar:http://www.jcg.com/bar/baz.jar!/com/foo/Quux.class
访问http服务器上Jar包内的目录:jar:http://www.jcg.com/bar/baz.jar!/com/foo/
访问本地文件系统上Jar包文件: jar:file:/c:/baz.jar!/
访问本地文件系统上Jar包内的文件: jar:file:/c:/baz.jar!/com/foo/Quux.class
访问本地文件系统上Jar包内的目录: jar:file:/c:/baz.jar!/com/foo/
JarURLConnection 使用示例:
1 获取jarfile:
URL url = new URL("jar:http://hostname/my.jar!/");
JarURLConnection conn = (JarURLConnection) url.openConnection();
JarFile jarfile = conn.getJarFile(); //获取jarFile
2 获取指定JarEntry
url = new URL("jar:file:/c:/almanac/my.jar!/com/mycompany/MyClass.class");
conn = (JarURLConnection) url.openConnection();
jarfile = conn.getJarFile();
entryName = conn.getEntryName();// com/mycompany/MyClass.class
jarFileUrl = conn.getJarFileURL();// file:/c:/almanac/my.jar
JarEntry jarEntry = conn.getJarEntry();//获取文件入口MyClass
3 使用classloader 加载指定文件
URL url = Thread.currentThread().getContextClassLoader().getResource("config/app.properties");
如果config/properties 是在jar包内部 :则url地址为 "jar:file:/c:/almanac/my.jar!/config/app.properties
如果config/properties 是在本工程内部: 则url 为 c:/almanac/config/app.properties
实际应用场景 :
1 :获取某个三方jar包中的所有class文件
public class TestRegex {
public static void main(String[] args) throws Exception{
String basePack = "org.junit";
//通过当前线程得到类加载器从而得到URL的枚举
URL url = Thread.currentThread().getContextClassLoader().getResource(basePack.replace(".", "/"));
String protocol = url.getProtocol();//大概是jar
if ("jar".equalsIgnoreCase(protocol)) {
//转换为JarURLConnection
JarURLConnection connection = (JarURLConnection) url.openConnection();
if (connection != null) {
JarFile jarFile = connection.getJarFile();
if (jarFile != null) {
//得到该jar文件下面的类实体
Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
while (jarEntryEnumeration.hasMoreElements()) {
JarEntry entry = jarEntryEnumeration.nextElement();
String jarEntryName = entry.getName();
//这里我们需要过滤不是class文件和不在basePack包名下的类
if (jarEntryName.contains(".class") && jarEntryName.replaceAll("/",".").startsWith(basePack)) {
String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
Class cls = Class.forName(className);
System.out.println(cls);
}
}
}
}
}
}
}
2 获取jar包内Manifest 内主函数 并执行
String JAR_URL = "jar:file:/C:/Users/ashraf_sarhan/simple-bean-1.0.jar!/";
String JAR_FILE_PATH = "file:/C:/Users/ashraf_sarhan/simple-bean-1.0.jar";
URL FileSysUrl = new URL(JAR_URL);
JarURLConnection jarURLConnection = (JarURLConnection)FileSysUrl.openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
Manifest manifest = jarFile.getManifest();
for (Entry entry : manifest.getMainAttributes().entrySet()) {
System.out.println(entry.getKey() +": "+ entry.getValue());
}
String mainClassName = manifest.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
URL[] classLoaderUrls = new URL[]{new URL(JAR_FILE_PATH)};
URLClassLoader urlClassLoader = new URLClassLoader(classLoaderUrls);
Class mianClass = urlClassLoader.loadClass(mainClassName);
Method method = mainClass.getMethod("main", String[].class);
String[] params = null;
method.invoke(null, (Object) params);
输出:
Manifest file attributes:
Build-Jdk: 1.7.0_40
Built-By: ashraf_sarhan
Manifest-Version: 1.0
Created-By: Apache
MavenMain-Class: com.jcg.Bean
Archiver-Version: Plexus ArchiverExternal JAR
Execution output:
Hello from loaded JAR class !!!