ChatGPT解决这个技术问题 Extra ChatGPT

What are Dynamic Proxy classes and why would I use one?

What is a use case for using a dynamic proxy?

How do they relate to bytecode generation and reflection?

Any recommended reading?

Nice explanation here opencredo.com/dynamic-proxies-java

C
Cybratech

I highly recommend this resource.

First of all, you must understand what the proxy pattern use case. Remember that the main intent of a proxy is to control access to the target object, rather than to enhance the functionality of the target object. The access control includes synchronization, authentication, remote access (RPC), lazy instantiation (Hibernate, Mybatis), AOP (transaction).

In contrast with static proxy, the dynamic proxy generates bytecode which requires Java reflection at runtime. With the dynamic approach you don't need to create the proxy class, which can lead to more convenience.


and the link is broken
Thanks for the link... Very helpful indeed.
I think this is the best answer. Other answers contain super long difficult setences that I will never be able to understand in my life. The link just helped me out, step by step.
K
Kevin Panko

A dynamic proxy class is a class that implements a list of interfaces specified at runtime such that a method invocation through one of the interfaces on an instance of the class will be encoded and dispatched to another object through a uniform interface. It can be used to create a type-safe proxy object for a list of interfaces without requiring pre-generation of the proxy class. Dynamic proxy classes are useful to an application or library that needs to provide type-safe reflective dispatch of invocations on objects that present interface APIs.

Dynamic Proxy Classes


Good answer, and a good example of this very thing is Spring Remoting, which has built in proxy capability for HTTP, RMI, EJB and JMS.
J
Jim P

I just came up with an interesting use for a dynamic proxy.

We were having some trouble a non-critical service that is coupled with another dependant service and wanted to explore ways of being fault-tolerant when that dependant service becomes unavailable.

So I wrote a LoadSheddingProxy that takes two delegates - one is the remote impl for the 'normal' service (after the JNDI lookup). The other object is a 'dummy' load-shedding impl. There is simple logic surrounding each method invoke that catches timeouts and diverts to the dummy for a certain length of time before retrying. Here's how I use it:

// This is part of your ServiceLocator class
public static MyServiceInterface getMyService() throws Exception
{
    MyServiceInterface loadShedder = new MyServiceInterface() {
        public Thingy[] getThingys(Stuff[] whatever) throws Exception {
            return new Thingy[0];
        }
        //... etc - basically a dummy version of your service goes here
    }           
    Context ctx = JndiUtil.getJNDIContext(MY_CLUSTER);
    try {
        MyServiceInterface impl = ((MyServiceHome) PortableRemoteObject.narrow(
                ctx.lookup(MyServiceHome.JNDI_NAME), 
                MyServiceHome.class)).create();
        // Here's where the proxy comes in
        return (MyService) Proxy.newProxyInstance(
            MyServiceHome.class.getClassLoader(),
        new Class[] { MyServiceInterface.class },
        new LoadSheddingProxy(MyServiceHome.JNDI_NAME, impl, loadShedder, 60000));  // 10 minute retry
    } catch (RemoteException e) {    // If we can't even look up the service we can fail by shedding load too
        logger.warn("Shedding load");
        return loadShedder;
    } finally {
        if (ctx != null) {
        ctx.close();
        }
    }
}

And here's the proxy:

public class LoadSheddingProxy implements InvocationHandler {

static final Logger logger = ApplicationLogger.getLogger(LoadSheddingProxy.class);

Object primaryImpl, loadDumpingImpl;
long retry;
String serviceName;
// map is static because we may have many instances of a proxy around repeatedly looked-up remote objects
static final Map<String, Long> servicesLastTimedOut = new HashMap<String, Long>();

public LoadSheddingProxy(String serviceName, Object primaryImpl, Object loadDumpingImpl, long retry)
{
    this.serviceName = serviceName;
    this.primaryImpl = primaryImpl;
    this.loadDumpingImpl = loadDumpingImpl;
    this.retry = retry;
}

public Object invoke(Object obj, Method m, Object[] args) throws Throwable
{
    try
    {
        if (!servicesLastTimedOut.containsKey(serviceName) || timeToRetry()) {
            Object ret = m.invoke(primaryImpl, args);
            servicesLastTimedOut.remove(serviceName);
            return ret;
        } 
        return m.invoke(loadDumpingImpl, args);
    }
    catch (InvocationTargetException e)
    {
        Throwable targetException = e.getTargetException();

        // DETECT TIMEOUT HERE SOMEHOW - not sure this is the way to do it???
        if (targetException instanceof RemoteException) {
            servicesLastTimedOut.put(serviceName, Long.valueOf(System.currentTimeMillis()));
        }
        throw targetException;
    }                    
}

private boolean timeToRetry() {
    long lastFailedAt = servicesLastTimedOut.get(serviceName).longValue();
    return (System.currentTimeMillis() - lastFailedAt) > retry;
}
}

D
Daniele Segato

The class java.lang.reflect.Proxy allows you to implement interfaces dynamically by handling method calls in an InvocationHandler. It is considered part of Java's reflection facility, but has nothing to do with bytecode generation.

Sun has a tutorial about the use of the Proxy class. Google helps, too.


m
miceuz

One use case is hibernate - it gives you objects implementing your model classes interface but under getters and setters there resides db related code. I.e. you use them as if they are just simple POJO, but actually there is much going on under cover.

For example - you just call a getter of lazily loaded property, but really the property (probably whole big object structure) gets fetched from the database.

You should check cglib library for more info.