6.5 Proxy
In the last section of this chapter, we will discuss the agency. Agents can create a new class that implements a given set of interfaces at runtime to use. Only we do not know at compile time when the need to implement an interface which only requires a proxy. For application programmers, this is not a common case, so if you are not interested in the Advanced Wizard, you can skip this section. However, for certain system programming applications, the flexibility provided by the agent can be very important.
6.5.1 When to use a proxy
Suppose you want to construct an object of a class that implements one or more interfaces, you may not know the exact nature of these interfaces at compile time. This is a difficult problem. To construct the actual classes, you can simply use the newInstance
method or using reflection to find the constructor. But you can not instantiate an interface. You need to define a new class in the program is running.
To solve this problem, some program generated code, put it in a file, invoke the compiler, and then load the class files generated. Of course, this is very slow, but it also needs to be deployed together with the compiler program. Proxy mechanism is a better solution. Acting classes can create new classes at runtime. Such a proxy class that implements the interface that you specify. In particular, the proxy class has the following methods:
- All methods specify the interfaces; and
Object
All methods defined in the classtoString
( ,equals
etc.).
However, you can not define new code for these methods at runtime. Instead, you must provide a handler is called. Invocation handler is to achieve InvocationHandler
any kind of object interface. The interface is only one way:
Object invoke(Object proxy, Method method, Object[] args)
Whenever you call a method on the proxy object, call handler invoke
method is called, Method
the parameters object and the original call as well. Then call handler must figure out how to handle the call.
6.5.2 Creating a proxy object
To create a proxy object, use the Proxy
class newProxyInstance
methods. The method takes three parameters:
- Class loader. As part of the Java security model, a different class loader can be used for platform and application classes, downloaded from the Internet and so on. We will discuss loaders in Volume II Chapter 9. In this example, we specify the loading platform and applications like "system class loader."
Class
An array of objects, each corresponding one of the interface to be achieved.- Call handler.
There are two issues. How do we define the handler? What can we do to generate a proxy object of it? Of course, the answer depends on the problem we want to solve the proxy mechanism. Agent can be used for various purposes, e.g.
- The method calls are routed to a remote server
- The user interface events associated with running programs in operation
- Tracing method calls for debugging purposes
In our example program, we use a proxy and call handlers to trace method calls. We define a TraceHandler
wrapper class that stores objects of a package. Its invoke
way to print only the name and parameters of the method to call, and then use the wrapped object as the implicit parameter called the method.
class TraceHandler implements InvocationHandler
{
private Object target;
public TraceHandler(Object t)
{
target = t;
}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable
{
// print method name and parameters
. . .
// invoke actual method
return m.invoke(target, args);
}
}
Here's how to construct a proxy object, every time you call one of its methods, the object will lead to stalking:
Object value = . . .;
// construct wrapper
var handler = new TraceHandler(value);
// construct proxy for one or more interfaces
var interfaces = new Class[] { Comparable.class};
Object proxy = Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[] { Comparable.class } , handler
);
Now, whenever proxy
the upper method call from one of the interfaces, will print out the method name and parameters, then value
the method call.
In the program shown in Listing 6.10, we use a proxy object tracking binary search. We use an integer of 1 - Agents fill an array of 1000. We then call the Arrays
class binarySearch
method to search for random integer array. Finally, we print matching elements.
var elements = new Object[1000];
// fill elements with proxies for the integers 1 . . . 1000
for (int i = 0; i < elements.length; i++)
{
Integer value = i + 1;
elements[i] = Proxy.newProxyInstance(. . .); // proxy for value;
}
// construct a random integer
Integer key = new Random().nextInt(elements.length) + 1;
// search for the key
int result = Arrays.binarySearch(elements, key);
// print match if found
if (result >= 0) System.out.println(elements[result]);
Integer
Class implements the Comparable
interface. Proxy object belongs to class definitions at runtime. (It has a name, such as $Proxy0
.) This class also implements the Comparable
interface. However, its compareTo
method call the proxy object handler invoke
method.
note
As you saw earlier in this chapter, Integer class actually implements
Comparable<Integer>
. However, at run time, all generic types will be cleared, and the proxy is using the originalComparable
class object of the class structure.
binarySearch
Call the following method:
if (elements[i].compareTo(key) < 0) . . .
Because we fill the array with a proxy object, it compareTo
calls the TraceHandler
class invoke
method. The printing method method name and parameters, and then packaging the Integer
call on the object compareTo
.
Finally, at the end of the sample program, we call
System.out.println(elements[result]);
println
Method on the proxy object call toString
, and the call can be redirected to a handler is called.
Here is the complete track running:
500.compareTo(288)
250.compareTo(288)
375.compareTo(288)
312.compareTo(288)
281.compareTo(288)
296.compareTo(288)
288.compareTo(288)
288.toString()
You can search interval will be shortened by half in each step to understand the binary search algorithm is how to locate the keys. Note that the toString
method is the agent, even though it does not belong to Comparable
the interface, as you will see in the next section, certain Object
method is always the proxy.
Listing 6.10 proxy / ProxyTest.java
package proxy;
import java.lang.reflect.*;
import java.util.*;
/**
* This program demonstrates the use of proxies.
* @version 1.01 2018-04-10
* @author Cay Horstmann
*/
public class ProxyTest
{
public static void main(String[] args)
{
var elements = new Object[1000];
// fill elements with proxies for the integers 1 . . . 1000
for (int i = 0; i < elements.length; i++)
{
Integer value = i + 1;
var handler = new TraceHandler(value);
Object proxy = Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[] { Comparable.class } , handler);
elements[i] = proxy;
}
// construct a random integer
Integer key = new Random().nextInt(elements.length) + 1;
// search for the key
int result = Arrays.binarySearch(elements, key);
// print match if found
if (result >= 0) System.out.println(elements[result]);
}
}
/**
* An invocation handler that prints out the method name and parameters, then
* invokes the original method
*/
class TraceHandler implements InvocationHandler
{
private Object target;
/**
* Constructs a TraceHandler
* @param t the implicit parameter of the method call
*/
public TraceHandler(Object t)
{
target = t;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
{
// print implicit argument
System.out.print(target);
// print method name
System.out.print("." + m.getName() + "(");
// print explicit arguments
if (args != null)
{
for (int i = 0; i < args.length; i++)
{
System.out.print(args[i]);
if (i < args.length - 1) System.out.print(", ");
}
}
System.out.println(")");
// invoke actual method
return m.invoke(target, args);
}
}
6.5.3 proxy class properties
Now that you have seen the role of the proxy class, so let's examine some of their properties. Remember, the proxy class is in the running program created dynamically. However, once they are created, they are just regular class, just like any other virtual machine in the same category.
All proxy classes extend the class Proxy
. Only one instance of a proxy class field - the invocation handler, it is in the Proxy
super class definition. Any other data required to perform the tasks proxy object must be stored in the call handler. For example, when our agents in the program shown in Listing 6.10 Comparable
object, the TraceHandler
packaging of the actual object.
All proxy classes override Object
classes toString
, equals
and hashCode
methods. As with all proxy methods that simply calling on the call handler invoke
. Object
Other methods (e.g., class clone
and getClass
) are not redefined.
Name of the proxy class is not defined. Oracle virtual machine Proxy
class string generated $Proxy
class names begin with.
For a particular class loader and ordered set of interfaces, only a proxy class. In other words, if the same class loader and an array of interfaces called twice newProxyInstance
methods, it will get two objects of the same class. You can also use the getProxyClass
method to get the class:
Class proxyClass = Proxy.getProxyClass(null, interfaces);
Proxy class is always public
and final
. If the proxy class implements all interfaces are public
, the agent class does not belong to any particular package. Otherwise, all the non- public
interface must belong to the same package, the proxy class also belongs to the package.
By calling the Proxy
class isProxyClass
method, we can test specific Class
whether the object represents a proxy class.
java.lang.reflect.InvocationHandler
1.3
Object invoke(Object proxy, Method method, Object[] args)
This method is defined to include the action that you want performed when the call to the proxy object.
java.lang.reflect.Proxy
1.3
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
Returns the proxy class to the given interface.static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler)
Configured to implement a new instance of the proxy class for a given interface. All of which invoke the given handler objectinvoke
method.static boolean isProxyClass(Class<?> cl)
Ifcl
a proxy class is returnedtrue
.
The final chapter describes the object-oriented features of the Java programming language. Interfaces, lambda expressions, and inner classes is that you often encounter the concept of cloning, loader and proxy service is an advanced technology, they are primarily of interest to designers and tools to build the library, rather than the application programmer. The program is now in the unusual circumstances you're ready to learn how to deal with in Chapter 7.