Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Usefulness of java dynamic proxies vs regular proxies

I need some advice to which scenarios a dynamic proxy would prove more useful than a regular proxy.

I've put alot of effort into learning how to use dynamic proxies effectively. In this question, set aside that frameworks like AspectJ can perform basically everything we try to achieve with dynamic proxies, or that e.g., CGLIB can be used to address some of the shortcomings of dynamic proxies.

Use cases

  • Decorators - e.g., perform logging on method invocation, or cache return values of complex operations
  • Uphold contract - That is, making sure parameters are within accepted range and return types conform to accepted values.
  • Adapter - Saw some clever article somewhere describing how this is useful. I rarely come across this design pattern though.

Are the others?

Dynamic proxy advantages

  • Decorator: Log all method invocations, e.g.,

public Object invoke(Object target, Method method, Object[] arguments) {
         System.out.println("before method " + method.getName());
         return method.invoke(obj, args);
     }
}

The decorator pattern is definately useful as it allows side effects to all proxies methods (although this behaviour is a book-example of using aspects ..).

  • Contract: In contrast to a regular proxy, we need not implement the full interface. E.g.,

public Object invoke(Object target, Method method, Object[] arguments) {
     if ("getValues".equals(method.getName()) {
         // check or transform parameters and/or return types, e.g., 
         return RangeUtils.validateResponse( method.invoke(obj, args) );
     }

     if ("getVersion".equals(method.getName()) {
         // another example with no delegation
         return 3;
     }
} 

The contract on the other hand only gives the benefit of avoiding the need to implement a complete interface. Then again, refactoring proxied methods would silently invalidate the dynamic proxy.

Conclusion

So what I see here is one real use case, and one questionable use case. What's your opinion?

like image 254
Johan Sjöberg Avatar asked Sep 12 '10 18:09

Johan Sjöberg


2 Answers

There are a number of potential uses for dynamic proxies beyond what you've described -

  1. Event publishing - on method x(), transparently call y() or send message z.
  2. Transaction management (for db connections or other transactional ops)
  3. Thread management - thread out expensive operations transparently.
  4. Performance tracking - timing operations checked by a CountdownLatch, for example.
  5. Connection management - thinking of APIs like Salesforce's Enterprise API that require clients of their service to start a session before executing any operations.
  6. Changing method parameters - in case you want to pass default values for nulls, if that's your sort of thing.

Those are just a few options in addition to validation and logging like you've described above. FWIW, JSR 303, a bean validation specification, has an AOP-style implementation in Hibernate Validator, so you don't need to implement it for your data objects specifically. Spring framework also has validation built in and has really nice integration with AspectJ for some of the stuff described here.

like image 70
Anthony Bishopric Avatar answered Sep 17 '22 15:09

Anthony Bishopric


Indeed AOP benefits most of the dynamic proxies. That's because you can create a dynamic proxy around an object that you don't know in advance.

Another useful side of a dynamic proxy is when you want to apply the same operation to all methods. With a static proxy you'd need a lot of duplicated code (on each proxied method you would need the same call to a method, and then delegate to the proxied object), and a dynamic proxy would minimize this.

Also note that Adapter and Decorator are separate patterns. They look like the Proxy pattern in the way they are implemented (by object composition), but they serve a different purpose:

  • the decorator pattern allows you to have multiple concrete decorators, thus adding functionality at runtime
  • the adapter pattern is meant to adapt an object to an unmatching interface. The best example I can think of is the EnumetationIterator - it adapts an Enumeration to the Iterator interface.
like image 44
Bozho Avatar answered Sep 17 '22 15:09

Bozho