Package java. Lang. Reflect;
Import java. Lang. Ref .*;
Import java. util .*;
Import sun. Misc. proxygenerator;
/**
* Example of using proxy
*
Interface TT {
String getst ();
}
Class STT implements TT {
Public String getst (){
Return "lqtest ";
}
}
Class myhandler implements invocationhandler {
Tt obj;
Public myhandler (tt obj ){
This. OBJ = OBJ;
}
Public object invoke (Object proxy, method, object [] ARGs) throws throwable {
System. Out. println ("this is my test ");
Return method. Invoke (OBJ, argS );
}
}
Stt t = new STT ();
Myhandler Hd = new myhandler (t );
TT k = (TT) proxy. newproxyinstance (TT. Class. getclassloader (), new class [] {TT. Class}, HD );
String rtst = K. getst ();
Class proxyclazz = proxy. getproxyclass (TT. Class. getclassloader (), new class [] {TT. Class });
TT k2 = (TT) proxyclazz. getconstructor (new class [] {invocationhandler. Class}). newinstance (new object [] {HD });
String rrst2 = k2.getst ();
* Both methods print strings on the console.
* The agent dynamically generates the class proxyclazz. Although we often load a *. Class file
* Byte arrays that conform to the class file format can also be loaded by classloader. If we are familiar with the class file format,
* We can use a programming method to dynamically generate a class, instead of simply generating a simple proxy class. This capability is not implemented by Sun.
*
* Proxy skills are often used in the AOP technology.
*
* Comment by liqiang
*
* @ Author Peter Jones
*
*/
Public class proxy implements java. Io. serializable {
// Proxy class prefix
Private Final Static string proxyclassnameprefix = "$ proxy ";
// The parameter type of the constructor
Private Final Static class [] constructorparams =
{Invocationhandler. Class };
// Cache corresponding to classloader and proxy class Cache
Private Static map loadertocache = new weakhashmap (3 );
// The identifier of the proxy class being created
Private Static object pendinggenerationmarker = new object ();
// Used to create a unique proxy class name
Private Static long nextuniquenumber = 0;
// The lock used to create the only type of name
Private Static object nextuniquenumberlock = new object ();
// Store all created proxy class objects
Private Static map proxyclasses =
Collections. synchronizedmap (New weakhashmap (3 ));
/**
* The invocation handler for this proxy instance.
* @ Serial
*/
Protected invocationhandler h;
/**
* Prohibits instantiation.
*/
Private proxy (){
}
// Constructor with invocationhandler object as the parameter
Protected proxy (invocationhandler h ){
This. H = h;
}
/**
*
* Dynamically generate proxy classes
* It has the following restrictions:
* 1 each element in the interface array should represent an interface and cannot represent a class or the original type.
* 2 duplicate types are not allowed.
* 3class. forname (I. getname (), false, Cl) = I indicates that the interface can be
* Access
* 4 the two interfaces cannot have the same method name and parameter list but different return values.
* 5 the maximum number of interfaces is 65535
* If the preceding conditions exist, illegalargumentexception is thrown.
* If the array contains null elements, nullpointerexception is thrown.
* Different proxy classes are generated for different interfaces in different order.
*
*
* @ Param loader loads the classloader of this proxy class
* @ Param interfaces interface list
*
*/
Public static class getproxyclass (classloader loader,
Class [] interfaces)
Throws illegalargumentexception
{
// Store dynamically generated class objects
Class proxyclass = NULL;
// Generate stringbuffer for the key value cached by proxy
Stringbuffer keybuffer = new stringbuffer ();
For (INT I = 0; I <interfaces. length; I ++ ){
Class interfaceclass = NULL;
Try {
// Determine whether an interface class object can be obtained by name
Interfaceclass =
Class. forname (interfaces [I]. getname (), false, loader );
} Catch (classnotfoundexception e ){
}
// If the interface class object cannot be obtained by name, an exception is thrown, and interfaceclass is null.
If (interfaceclass! = Interfaces [I]) {
Throw new illegalargumentexception (
Interfaces [I] + "is not visible from Class Loader ");
}
// If the element in the interface array is not an interface, an exception is thrown.
If (! Interfaceclass. isinterface ()){
Throw new illegalargumentexception (
Interfaceclass. getname () + "is not an interface ");
}
// Use ";" to connect to the interface name and generate the cache key
Keybuffer. append (interfaces [I]. getname (). append (';');
}
// Generate the cache key value of string, so that the collection efficiency is not high.
String key = keybuffer. tostring ();
/*
* Find or create the proxy class cache for the class loader.
*/
Map cache;
Synchronized (loadertocache ){
// Obtain the proxy class cache of the corresponding classloader object
Cache = (MAP) loadertocache. Get (loader );
If (Cache = NULL ){
// If there is no cache corresponding to this classloader, create it
Cache = new hashmap (3 );
Loadertocache. Put (loader, cache );
}
// The subsequent part of this method, loadertocache, is still valid, but not synchronized because
// Mapping is removed only when the loader cannot be touched in a timely manner.
}
// Use the string key value to find the proxy class. There are three possible cases:
// 1 if the current cache does not have this proxy class, null is returned.
// 2 If the proxy class is being created, the pendinggenerationmarker object is returned.
// 3 if the proxy class has been created, the weakreference object is returned.
Synchronized (cache ){
/*
* Note that we need not worry about reaping the cache
* Entries with cleared weak references because if a proxy class
* Has been garbage collected, its class loader will have been
* Garbage collected as well, so the entire cache will be reaped
* From the loadertocache map.
*/
Do {
// Retrieve the reference object that encapsulates the proxy class object through the interface list key value
Object value = cache. Get (key );
If (value instanceof reference ){
// Retrieve the proxy class object from the reference object
Proxyclass = (class) (reference) value). Get ();
}
If (proxyclass! = NULL ){
// If the proxy class object has been created, return directly
Return proxyclass;
} Else if (value = pendinggenerationmarker ){
// Wait if the proxy object is being created
Try {
Cache. Wait ();
} Catch (interruptedexception e ){
// The process of creating a class is short and set to a long time. Therefore, the interrupt processing is ignored here.
}
// If the proxy is created or interrupted, the proxy class object in the cache will continue to be obtained through the key value.
Continue;
} Else {
// If it is not created, it indicates that it is being created
Cache. Put (Key, pendinggenerationmarker );
// Jump out of the loop and create this proxy class
Break;
}
} While (true );
}
Try {
// Proxy class package
String proxypkg = NULL;
/*
* Record the package of a non-public proxy interface so that
* Proxy class will be defined in the same package. Verify that
* All non-public proxy interfaces are in the same package.
*/
For (INT I = 0; I <interfaces. length; I ++ ){
// Obtain the descriptor of each interface
Int flags = interfaces [I]. getmodifiers ();
If (! Modifier. ispublic (flags) {// not common
String name = interfaces [I]. getname ();
Int n = Name. lastindexof ('.');
// Get the package name. If there is no package name, use a Null String
String PKG = (n =-1 )? "": Name. substring (0, n + 1 ));
If (proxypkg = NULL) {// The first Interface
Proxypkg = PKG;
} Else if (! PKG. Equals (proxypkg )){
// If the interface is not public and is not in the same package, an exception is thrown.
Throw new illegalargumentexception (
"Non-public interfaces from different packages ");
}
}
}
If (proxypkg = NULL) {// if there is no non-public interface
Proxypkg = ""; // use an anonymous package
}
// A block is used.
{
/*
* Choose a name for the proxy class to generate.
*/
Long num;
Synchronized (nextuniquenumberlock ){
// Static attributes are used as locks to protect data in the synchronization area.
// Because num is of the long type, the original object cannot be locked (only the class can be locked)
// Performance will be wasted if the entire object is locked
// Use a lock object to protect Multiple Data (objects, original types) at the same time
Num = nextuniquenumber ++;
}
// Spell out a new class name. the spelling of the class name is the package name + $ proxy + unique long value.
String proxyname = proxypkg + proxyclassnameprefix + num;
// Generate the class bytecode
Byte [] proxyclassfile = proxygenerator. generateproxyclass (
Proxyname, interfaces );
Try {
// Load this class
Proxyclass = defineclass0 (loader, proxyname,
Proxyclassfile, 0, proxyclassfile. Length );
} Catch (classformaterror e ){
Throw new illegalargumentexception (E. tostring ());
}
}
// Place the newly created Class Object to the set that stores the Class Object of the created proxy class
Proxyclasses. Put (proxyclass, null );
} Finally {
Synchronized (cache ){
If (proxyclass! = NULL ){
// If it is successfully created, the value in the cache will be reset. It turns out to be pendinggenerationmarker.
Cache. Put (Key, new weakreference (proxyclass ));
} Else {
// If creation fails, the corresponding key is deleted.
Cache. Remove (key );
}
// Wake up all pending processes because they encounter a proxy class being created
Cache. policyall ();
}
}
Return proxyclass;
}
/**
* Quick method for creating a proxy object
*
* @ Param loader loads the classloader of this proxy class
* @ Param interfaces interface list
* @ Param H invocationhandler object
*
*/
Public static object newproxyinstance (classloader loader,
Class [] interfaces,
Invocationhandler H)
Throws illegalargumentexception
{
If (H = NULL ){
// If invocationhandler is null, an exception is thrown.
Throw new nullpointerexception ();
}
// Obtain the proxy class
Class Cl = getproxyclass (loader, interfaces );
Try {
// Obtain the constructor with an invocationhandler object parameter
Constructor cons = Cl. getconstructor (constructorparams );
// Create an instance
Return (object) cons. newinstance (new object [] {H });
} Catch (nosuchmethodexception e ){
Throw new internalerror (E. tostring ());
} Catch (illegalaccessexception e ){
Throw new internalerror (E. tostring ());
} Catch (instantiationexception e ){
Throw new internalerror (E. tostring ());
} Catch (invocationtargetexception e ){
Throw new internalerror (E. tostring ());
}
}
// Determine whether the specified class is created
Public static Boolean isproxyclass (class Cl ){
If (CL = NULL ){
Throw new nullpointerexception ();
}
Return proxyclasses. containskey (CL );
}
// If proxy is a proxy object, get its getinvocationhandler object; otherwise, an exception is thrown.
Public static invocationhandler getinvocationhandler (Object proxy)
Throws illegalargumentexception
{
// Check whether the proxy object is an object of the generated proxy class.
If (! Isproxyclass (proxy. getclass ())){
Throw new illegalargumentexception ("not a proxy instance ");
}
// If yes, transition
Proxy P = (proxy) proxy;
Return p. h;
}
// Load the local method of the class
Private Static native class defineclass0 (classloader loader, string name,
Byte [] B, int off, int Len );
}