In software design, a proxy pattern is one of the popular GOF design patterns.
A proxy is a class functioning as an interface to something else, it could be an interface to some business logic, network, file, or anything else.
This can also be seen as a wrapper around something core or real, main goal of a proxy is to add abstraction to get something extra it could be logging, permission check, cache, metric collection, etc.
We interact with proxies in real life. Take a example of bank interaction via ATM
ATM acts like a proxy to the bank branch, it allows to do almost everything that can be done at a branch.
In software we see many variations of a proxy, some of the examples are in IO API in java
Another variation is chain of responsibility.
In java proxy can be of 2 types it can be static and dynamic, lets look at a static proxy example.
Static Proxy
We are building Big Collection that allows to store unlimited data, our big collection interface looks like
public interface BigCollection<V> {
void add(V value);
boolean exists(V value);
void forEach(Consumer<V> c);
}
Static proxy will have same interface as original interface and will manually delegate calls to real object, it will look something like below.
public class BigCollectionProxy<V> implements BigCollection<V> {
private final Supplier<BigCollection<V>> supplier;
private final BigCollection<V> realObject;
public BigCollectionProxy(Supplier<BigCollection<V>> supplier) {
this.supplier = supplier;
this.realObject = supplier.get();
}
@Override
public void add(V value) {
realObject.add(value);
}
@Override
public boolean exists(V value) {
return realObject.exists(value);
}
@Override
public void forEach(Consumer<V> c) {
realObject.forEach(c);
}
}
Client API for using the proxy will look something like below
BigCollection<String> collection = new BigCollectionProxy<>(AwsCollection::new);
collection.add("Value1");
collection.add("Value2");
collection.forEach(System.out::println);
System.out.println("Exists " + collection.exists("Value2"));
Static proxy is easy to implement but it has got few problems
- Manual delegation is painful and very verbose.
- Any changes in interface required proxy also to implement changes.
- Special treatment to functions that are part of language ecosystem like equals, hashcode,getClass etc.
- and as name suggest it is static, can't change the behavior at runtime.
Dynamic proxy solves issue with static proxy, lets look at dynamic proxy.
Dynamic Proxy
Dynamic proxy creates proxy at runtime, it is very flexible and convenient.
JDK has dynamic proxy API since 1.3 that allows to create dynamic proxy using very simple API
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler);
(BigCollection<V>) Proxy.newProxyInstance(BigCollection.class.getClassLoader(),
new Class<?>[]{BigCollection.class},
new BigCollectionDynamicProxy(supplier.get()));
This proxy looks exactly like BigCollection implementation and can be passed around. This also does not have the verbosity of static/hand crafted proxy, full proxy looks something like below
public class BigCollectionDynamicProxy implements InvocationHandler {
private final Object realObject;
public BigCollectionDynamicProxy(Object realObject) {
this.realObject = realObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(realObject, args);
}
public static <V> BigCollection<V> create(Supplier<BigCollection<V>> supplier) {
return (BigCollection<V>) Proxy.newProxyInstance(BigCollection.class.getClassLoader(),
new Class<?>[]{BigCollection.class},
new BigCollectionDynamicProxy(supplier.get()));
}
}
Java reflection makes it easy to delegate calls to underlying real object.
Dynamic Proxy Use case
- Timing of method execution
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.nanoTime();
try {
return method.invoke(realObject, args);
} finally {
long total = System.nanoTime() - start;
System.out.println(String.format("Function %s took %s nano seconds", method.getName(), total));
}
}
- Single thread execution
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
synchronized (realObject) {
return method.invoke(realObject, args);
}
}
- Asynchronous Execution.
es.submit(() -> {
try {
System.out.println("Using thread " + Thread.currentThread().getName());
method.invoke(realObject, args);
} catch (Exception e) {
e.printStackTrace();
}
- Logging.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.nanoTime();
try {
return method.invoke(realObject, args);
} finally {
long total = System.nanoTime() - start;
System.out.println(String.format("Function %s took %s nano seconds", method.getName(), total));
}
}
Dynamic Proxy Tradeoff
Methodhandle returns back in java 8
Boxing & Unboxing overhead are really hard to resolve and this will be always overhead for dynamic proxy unless some code generation technique is used.
Code used in this post is available @ proxy github project
"jaifal price
ReplyDeletebuy badam online
goond
best quality badam
best quality walnuts
chuara benefits
khumani fruit
best badam quality
gooseberry online shopping
sugar badam tree
kishmish online
gurbandi badam price per kg
sama ke chawal price
kashmiri mirch sabut
best quality anjeer
best quality almonds
khaand
best quality kaju in india
kali kishmish price
kala chana price per kg
almond lowest price
moong sabut price
saunf rate per kg
fresh amla online
buy supari online
sauf price
bura price
kandhari kishmish
kale chane protein
kali masoor ki daal
gurbandi badam price
khumani dry fruit
white mirch
black kishmish
star fool
singhara atta price of 1kg
alachandalu
"
"jaifal price
ReplyDeletebuy badam online
goond
best quality badam
best quality walnuts
chuara benefits
khumani fruit
best badam quality
gooseberry online shopping
sugar badam tree
kishmish online
gurbandi badam price per kg
sama ke chawal price
kashmiri mirch sabut
best quality anjeer
best quality almonds
khaand
best quality kaju in india
kali kishmish price
kala chana price per kg
almond lowest price
moong sabut price
saunf rate per kg
fresh amla online
buy supari online
sauf price
bura price
kandhari kishmish
kale chane protein
kali masoor ki daal
gurbandi badam price
khumani dry fruit
white mirch
black kishmish
star fool
singhara atta price of 1kg
alachandalu
"
"We at Farmonics provide premium quality products to our customers as we are on n mission to provide good quality products at the doorsteps of every household we deal with in Kirana, seeds nuts,dry fruits, pulses, spices, etc.
ReplyDeleteKirana include badi elaichi, elaichi,dal chinni, sauf, oregano , chilli flakes,etc
Seeds include pumpkin seeds, muskmelon seeds, tarbuja seeds , mix seeds, etc.
Dry fruits include almonds, Kaju, Pista, akroat, anjeer, kishmish, etc.
Pulses include Rajma, ahar, moong, urad, choole, etc.
Spices include mirch, haldi, jeera, daniya, amchoor, etc.
You can explore our products by visiting our website farmonics
"
"We at Farmonics provide premium quality products to our customers as we are on n mission to provide good quality products at the doorsteps of every household we deal with in Kirana, seeds nuts,dry fruits, pulses, spices, etc.
ReplyDeleteKirana include badi elaichi, elaichi,dal chinni, sauf, oregano , chilli flakes,etc
Seeds include pumpkin seeds, muskmelon seeds, tarbuja seeds , mix seeds, etc.
Dry fruits include almonds, Kaju, Pista, akroat, anjeer, kishmish, etc.
Pulses include Rajma, ahar, moong, urad, choole, etc.
Spices include mirch, haldi, jeera, daniya, amchoor, etc.
You can explore our products by visiting our website farmonics
"