Use classloader to call external jar packages

Source: Internet
Author: User

We all know that every running thread has a member contextclassloader, which is used to dynamically load other classes at runtime.

The default contextclassloader of the system is systemclassloader. Therefore, Java programs can use classes in JVM, $ java_home/JRE/lib/EXT/, and classes in $ classpath/during execution, for non-default jar files, you can only manually add them in the configuration environment.

But in fact, we can change the contextclassloader behavior of the current thread through thread. currentthread (). setcontextclassloader () to load external jar in the program.

PS:
The working principle of classloader is:
1) when a thread needs to use a class, contextclassloader will be requested to load the class
2) contextclassloader requests its parent classloader to complete the load request.
3) if the parent classloader cannot load the class, contextclassloader tries to load the class by itself.

 

Package org. loon. Framework. jar;

/***//**
* <P> title: loonframework </P>
* <P> Description: jarloader, used for external operations of the jar package </P>
* <P> copyright: Copyright (c) 2007 </P>
* <P> company: loonframework </P>
* @ Author chenpeng
* @ Email: ceponline@yahoo.com.cn
* @ Version 0.1
*/
Import java. Io. bufferedinputstream;
Import java. Io. bytearrayinputstream;
Import java. Io. bytearrayoutputstream;
Import java. Io. file;
Import java. Io. fileinputstream;
Import java. Io. filenotfoundexception;
Import java. Io. ioexception;
Import java. Io. inputstream;
Import java. Lang. Reflect. method;
Import java.net. malformedurlexception;
Import java.net. url;
Import java. util. arraylist;
Import java. util. hashmap;
Import java. util. hashtable;
Import java. util. Jar. jarentry;
Import java. util. Jar. jarinputstream;
Import java. util. Jar. manifest;

Public class jarloader extends classloader ...{
// Resource Cache
Public static hashtable resources = new hashtable ();
 
Public static jarloader loader = new jarloader ();

Public static class load (byte [] Resource) throws exception ...{
// Full name of the class in which the main function is located
String mainclassname = "";
// Class resource and entity Cache
Arraylist classnames = new arraylist ();
Arraylist classbuffers = new arraylist ();
// Storage dependency class
Hashmap depends = new hashmap ();
// Convert byte [] to jarinputstream
Jarinputstream jar = new jarinputstream (New bytearrayinputstream (
Resource ));
Manifest manifest = jar. getmanifest ();
// When the main-class is declared, obtain the full name of the class where the main function is located.
If (manifest! = NULL )...{
Mainclassname = manifest. getmainattributes (). getvalue ("Main-class ");
}
// Obtain the jarentry of each compressed file encapsulated in the corresponding JAR file in sequence
Jarentry entry;
While (Entry = jar. getnextjarentry ())! = NULL )...{
// When the found entry is a class
If (entry. getname (). tolowercase (). endswith (". Class "))...{
// Change the class path to the full name of the class
String name = entry. getname (). substring (0,
Entry. getname (). Length ()-". Class". Length (). Replace (
'/','.');
// Load the class
Byte [] DATA = getresourcedata (jar );
// Cache class name and Data
Classnames. Add (name );
Classbuffers. Add (data );

} Else ...{
// When the non-class end but the start character is '/'
If (entry. getname (). charat (0) = '/')...{
Resources. Put (entry. getname (), getresourcedata (jar ));
// Otherwise append '/' and then Cache
} Else ...{
Resources. Put ("/" + entry. getname (), getresourcedata (jar ));
}
}
}
// When the obtained main-class name is not blank
While (classnames. Size ()> 0 )...{
// Obtain the full length of the class path
Int n = classnames. Size ();
For (INT I = classnames. Size ()-1; I> = 0; I --)...{
Try ...{
// Query the specified class
Loader. defineclass (string) classnames. Get (I ),
(Byte []) classbuffers. Get (I), 0,
(Byte []) classbuffers. Get (I). Length );
// Obtain the class name
String pkname = (string) classnames. Get (I );
If (pkname. lastindexof ('.')> = 0 )...{
Pkname = pkname
. Substring (0, pkname. lastindexof ('.'));
If (loader. getpackage (pkname) = NULL )...{
Loader. definepackage (pkname, null,
Null, null );
}
}
// Delete the buffer after the query
Classnames. Remove (I );
Classbuffers. Remove (I );
} Catch (noclassdeffounderror e )...{
Depends. Put (string) classnames. Get (I), E. getmessage ()
. Replaceall ("/","."));
} Catch (unsupportedclassversionerror e )...{
// JRE version error message
Throw new unsupportedclassversionerror (classnames. Get (I)
+ "," + System. getproperty ("Java. VM. Name") + ""
+ System. getproperty ("Java. VM. Version") + ")");
}
}
If (n = classnames. Size ())...{
For (INT I = 0; I <classnames. Size (); I ++ )...{
System. Err. println ("noclassdeffounderror :"
+ Classnames. Get (I ));
String classname = (string) classnames. Get (I );
While (depends. containskey (classname ))...{
Classname = (string) depends. Get (classname );
}
}
Break;
}
}
Try ...{
// Load
Thread. currentthread (). setcontextclassloader (loader );
// Obtain the specified class. The method for searching other classes is similar.
Return class. forname (mainclassname, true, loader );
} Catch (classnotfoundexception e )...{
String classname = mainclassname;
While (depends. containskey (classname ))...{
Classname = (string) depends. Get (classname );
}
Throw new classnotfoundexception (classname );
}
}

/***//**
* Get the byte [] format of the specified path File
* @ Param name
* @ Return
*/
Final Static public byte [] getdatasource (string name )...{
Fileinputstream fileinput;
Try ...{
Fileinput = new fileinputstream (new file (name ));
} Catch (filenotfoundexception e )...{
Fileinput = NULL;
}
Bufferedinputstream bufferedinput = new bufferedinputstream (fileinput );
Return getdatasource (bufferedinput );
}

/***//**
* Obtain the byte [] Form of the specified inputstream
* @ Param name
* @ Return
*/
Final Static public byte [] getdatasource (inputstream is )...{
If (is = NULL )...{
Return NULL;
}
Bytearrayoutputstream = new bytearrayoutputstream ();
Byte [] arraybyte = NULL;
Try ...{
Byte [] bytes = new byte [1, 8192];
Bytes = new byte [is. Available ()];
Int read;
While (read = is. Read (bytes)> = 0 )...{
Bytearrayoutputstream. Write (bytes, 0, read );
}
Arraybyte = bytearrayoutputstream. tobytearray ();
} Catch (ioexception e )...{
Return NULL;
} Finally ...{
Try ...{
If (bytearrayoutputstream! = NULL )...{
Bytearrayoutputstream. Close ();
Bytearrayoutputstream = NULL;
}
If (is! = NULL )...{
Is. Close ();
Is = NULL;
}

} Catch (ioexception e )...{
}
}
Return arraybyte;
}

/***//**
* Get the byte [] Form of the specified jarinputstream
* @ Param jar
* @ Return
* @ Throws ioexception
*/
Final Static private byte [] getresourcedata (jarinputstream jar)
Throws ioexception ...{
Bytearrayoutputstream DATA = new bytearrayoutputstream ();
Byte [] buffer = new byte [8192];
Int size;
While (jar. Available ()> 0 )...{
Size = jar. Read (buffer );
If (size> 0 )...{
Data. Write (buffer, 0, size );
}
}
Return data. tobytearray ();
}

/***//**
* Reload the getresource and check whether it contains repeated
*/
Public URL getresource (string name )...{
If (resources. containskey ("/" + name ))...{
Try ...{
Return new URL ("file: //" + name );
} Catch (malformedurlexception e )...{
E. printstacktrace ();
}
}
Return super. getresource (name );
}

/***//**
* Execute the specified class
* @ Param clz
* @ Param methodname
* @ Param ARGs
*/
Public static void callvoidmethod (class clz, string methodname,
String [] ARGs )...{
Class [] Arg = new class [1];
Arg [0] = args. getclass ();
Try ...{
Method method = clz. getmethod (methodname, ARG );
Object [] inarg = new object [1];
Inarg [0] = ARGs;
Method. Invoke (clz, inarg );
} Catch (exception e )...{
System. Err. println (E. getmessage ());
}
}

/***//**
* Reload the getresourceasstream and check whether it contains repeated
*/
Public inputstream getresourceasstream (string name )...{
If (name. charat (0) = '/')...{
Name = Name. substring (1 );
}
If (resources. containskey ("/" + name ))...{
Return new bytearrayinputstream (byte []) resources. Get ("/" + name ));
}
Return super. getresourceasstream (name );
}

}

Running example:

Package org. loon. Framework. jar;

/***//**
* <P>
* Title: loonframework
* </P>
* <P>
* Description: Start the jar package from the external
* </P>
* <P>
* Copyright: Copyright (c) 2007
* </P>
* <P>
* Company: loonframework
* </P>
*
* @ Author chenpeng
* @ Email: ceponline@yahoo.com.cn
* @ Version 0.1
*/
Public class jartest ...{

Public static void main (string [] ARGs )...{
// Convert the jar package into byte []
Byte [] Resource = jarloader. getdatasource ("D:/fps_test.jar ");
Try ...{
// Obtain the class of the main function through byte []
Class clz = jarloader. Load (Resource );
// Call the main function
Jarloader. callvoidmethod (clz, "Main", new string []... {""});
} Catch (exception e )...{
E. getstacktrace ();
}

}

}

Even if the specified jar package is not added to Lib, the program is started successfully.

However, there is a drawback. Without optimization, the speed of loading external packages directly will cause a great loss in JVM.

We can see that the FPS value is reduced to about 50% of the normal value (for this FPS instance, see my previous articles on csdn ), therefore, it is not suitable to be directly applied to class calls in jar that require complex operations. (If you are interested, you can optimize them in the code, another example I wrote in my project is much faster than this one ). However, external jar calls with a small amount of computing are very convenient.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.