0

Proxy is used to intercept OR to surrogate OR change existing functionality of target object without modifying it, but same thing we can achieve using normal java class by inheriting target class & overriding it's methods.
Then what is exact usage of it ? How it is different & efficient from normal java class ?

0

4 Answers 4

3

Proxy is just a name given to a class following the proxy design pattern. It is a normal java class.

For further reading, check Proxy pattern in Java

Sign up to request clarification or add additional context in comments.

2 Comments

yes it is design pattern, but we can achieve using normal java classes as well ? then why it is used instead of ?
Instead of what? Inheritance? You can't achieve the main goal of proxy design pattern with inheritance. You should read the article given by Smile. And I don't understand why the modeling of this design implies for you the use of "not normal java classes"
2

You can implement proxies with ordinary classes, e.g.

Iterable<String> i = Arrays.asList("hello", "world");
Iterable<String> proxy = new Iterable<String>() {
    @Override
    public Iterator<String> iterator() {
        System.out.println("Entering .iterator()");
        try {
            return i.iterator();
        }
        finally {
            System.out.println("Exiting .iterator()");
        }
    }
};

for(String s: proxy) {
    System.out.println(s);
}
Entering .iterator()
Exiting .iterator()
hello
world

The advantage of dynamic proxy generators, like java.lang.reflect.Proxy, are that they allow to handle an arbitrary number of interface methods with a single handler method and don’t require hardcoding of the interfaces to implement. The interfaces do not even need to exist at compile-time.

For example:

List<String> i = Arrays.asList("hello", "world");

final class MyInvocationHandler implements InvocationHandler {
    private final Object target;
    public MyInvocationHandler(Object t) { target = t; }
    @Override public Object invoke(
                     Object proxy, Method method, Object[] args) throws Throwable {
        String name = method.getDeclaringClass().getSimpleName()+'.'+method.getName();
        System.out.println("  Entering "+name);
        try {
            Object o = method.invoke(target, args);
            final Class<?> rt = method.getReturnType();
            if(rt != Void.TYPE) System.out.println("    => "+o);
            return o == null || !rt.isInterface()? o:
                Proxy.newProxyInstance(null,new Class<?>[]{rt},new MyInvocationHandler(o));
        }
        finally {
            System.out.println("  Exiting "+name);
        }
    }
}
List<String> proxy = (List<String>)
    Proxy.newProxyInstance(null, new Class<?>[]{List.class}, new MyInvocationHandler(i));

System.out.println("*** for loop:");
for(String s: proxy) System.out.println(s);

System.out.println();
System.out.println("*** stream:");
proxy.stream().forEach(System.out::println);

System.out.println();
System.out.println("*** parallel stream:");
StreamSupport.stream(proxy.spliterator(), true).forEach(System.out::println);
*** for loop:
  Entering List.iterator
    => java.util.Arrays$ArrayItr@5cb0d902
  Exiting List.iterator
  Entering Iterator.hasNext
    => true
  Exiting Iterator.hasNext
  Entering Iterator.next
    => hello
  Exiting Iterator.next
hello
  Entering Iterator.hasNext
    => true
  Exiting Iterator.hasNext
  Entering Iterator.next
    => world
  Exiting Iterator.next
world
  Entering Iterator.hasNext
    => false
  Exiting Iterator.hasNext

*** stream:
  Entering Collection.stream
    => java.util.stream.ReferencePipeline$Head@443b7951
  Exiting Collection.stream
  Entering Stream.forEach
hello
world
  Exiting Stream.forEach

*** parallel stream:
  Entering List.spliterator
    => java.util.Spliterators$ArraySpliterator@5d6f64b1
  Exiting List.spliterator
  Entering Spliterator.characteristics
    => 16464
  Exiting Spliterator.characteristics
  Entering Spliterator.estimateSize
    => 2
  Exiting Spliterator.estimateSize
  Entering Spliterator.trySplit
    => java.util.Spliterators$ArraySpliterator@6aa8ceb6
  Exiting Spliterator.trySplit
  Entering Spliterator.estimateSize
    => 1
  Exiting Spliterator.estimateSize
  Entering Spliterator.getExactSizeIfKnown
    => 1
  Exiting Spliterator.getExactSizeIfKnown
  Entering Spliterator.forEachRemaining
world
  Exiting Spliterator.forEachRemaining
  Entering Spliterator.estimateSize
    => 1
  Exiting Spliterator.estimateSize
  Entering Spliterator.getExactSizeIfKnown
    => 1
  Exiting Spliterator.getExactSizeIfKnown
  Entering Spliterator.forEachRemaining
hello
  Exiting Spliterator.forEachRemaining

This demonstrates how a single handler method can decorate the List interface with two dozen methods and dynamically decorate return values when the return type is an interface, decorating four interfaces in the example code, and it would decorate more when you change the test case.

Just try to implement this with ordinary implementations of those interfaces and you’ll immediately recognize the advantage of the dynamic proxy generator. Not to speak of the ability to adapt to new interfaces when the show up…


A different use case would be dynamic component binding. This may look like this:

JButton component = new JButton("example");
String event = "action";

BeanInfo bi = Introspector.getBeanInfo(component.getClass());
for(EventSetDescriptor ed: bi.getEventSetDescriptors()) {
    if(ed.getName().equals(event)) {
        System.out.println("listening to "+ed.getDisplayName());
        final Class<?> listener = ed.getListenerType();
        ed.getAddListenerMethod().invoke(component, 
            Proxy.newProxyInstance(listener.getClassLoader(), new Class<?>[]{listener},
                new InvocationHandler() {
                    @Override
                    public Object invoke(
                           Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("event "+method.getName()+Arrays.toString(args));
                        return null;
                    }
                })
        );                
    }
}

component.doClick();
listening to action
event actionPerformed[java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=example,when=1579865741229,modifiers=] on javax.swing.JButton[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.5,border=javax.swing.plaf.BorderUIResource$CompoundBorderUIResource@5fdba6f9,flags=296,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=14,bottom=2,right=14],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=example,defaultCapable=true]]

There’s already java.beans.EventHandler providing exactly this functionality for the common use case of setting another component’s property in response to an event.

Comments

0

Proxy class is a class that is operating like an interface for another class or a group of classes.

It can be considered like a Smart Interface

Proxy design pattern can be used to add some decision-making (access control, rate limiting, environment setting, etc) before instantiating an object.

One of the most popular examples of Proxy pattern can be found in Browser UI test automation.

Example use case of proxy pattern

Suppose that there are 3 browser objects, defined by 3 different classes - InternetExplorer, Firefox, Chrome.

If the requirement is to run a test case on a browser selected at runtime, then the Proxy pattern can become helpful.

A Proxy class called 'Browser' that takes 'browser name' as the input and instantiates the desired browser at runtime can be a great solution in this scenario.

Comments

0

The term Proxy is vague but if you are asking about Java Dynamic Proxy, they are generated at runtime so they provides lots of flexibilities.

There are many ways you can generate proxies:

  • using java.lang.reflect.InvocationHandler
  • using libraries like cglib, bytebuddy, jassist, asm etc

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.