Introduction
A proxy forces object method calls to occur indirectly through the proxy object, which acts as a surrogate or delegate
for the underlying object being proxied. Proxy objects are usually declared so that the client objects have no indication that they have a proxy object instance.
java.lang.reflect.Proxy
class has a few drawbacks:
- It uses reflection extensively.
- Code written to handle methods is not clean.
The invoke
method becomes ugly at times.
Using the code
Proxy.newProxyInstance(Class clazz, Map<Class, Object> interfaceMap, Object... args)
clazz - Proxy base class
interfaceMap - key is interface class and value is
- either object implementing the interface
- or concrete class (not abstract) implementing the respective interface and having public zero argument constructor
args - Arguments passed to constructor to create instance of proxy class (same give in clazz parameter)
Base class is just a simple class (with at least one non private constructor). If signature of method is same as one of the interfaces then that function will be called instead of the one provided in actual implementation (i.e. value in interfaceMap
).
You can also make Base class abstract implementing the interfaces and defining only selective methods.
Example,
public class Base {
public Object call() throws Exception {
System.out.println("Call start");
Object o = (Proxy.<Callable> getInnerObject(this, Callable.class))
.call();
System.out.println("Call end");
return o;
}
public int compareTo(Object o) {
System.out.println("compareTo called with argument - " + o);
return 0;
}
}
The above compareTo
will be called instead implementation passed in interfaceMap
interfaceMap.put(Comparable.class, new Comparable(){
@Override
public int compareTo(Object o) {
System.out.println("This will not be called as inner object is not accessed from base class.");
return 0;
}
});
interfaceMap.put(Runnable.class, MyRunnable.class);
interfaceMap.put(Callable.class, MyCallable.class);
Runnable runnable = (Runnable)Proxy.newProxyInstance(Base.class, interfaceMap);
Thread thread = new Thread(runnable);
thread.start();
You can access the actual implementation object (i.e. value in interfaceMap) by using something like:
Callable callable = Proxy.<Callable> getInnerObject(this, Callable.class);
Where this
is the instance of base class and Callable.class
is the key passed in interfaceMap.
If you want that nobody else should be able to access you inner objects directly (i.e. by using Proxy.<Callable> getInnerObject
) you can use an overloaded method of newProxyInstance which restricts of calling this function of any other class other than Base class.
Bytecode manipulation is used only first time newProxyInstance
is called.