Подтвердить что ты не робот

Что такое классы динамического прокси и почему я должен использовать его?

Что такое использование динамического прокси-сервера?

Как они относятся к генерации и отражению байткода?

Любое рекомендуемое чтение?

4b9b3361

Ответ 1

Я очень рекомендую этот ресурс .

Прежде всего, вы должны понять, что используется для использования прокси-шаблона. Помните, что основной целью прокси-сервера является контроль доступа к целевого объекта, а не для повышения функциональности целевой объект. Управление доступом включает в себя синхронизацию, аутентификацию, удаленный доступ (RPC), ленивую инстанцию ​​(Hibernate, Mybatis), AOP (транзакция).

В отличие от статического прокси динамический прокси генерирует байт-код, который требует отражения Java во время выполнения. С динамикой вам не нужно класть класс прокси, что может привести к большему удобству.

Ответ 2

Динамический прокси-класс - это класс, который реализует список интерфейсы, указанные во время выполнения, так что вызов метода через один из интерфейсов на экземпляре класса будет закодирован и отправляется на другой объект через единый интерфейс. Может быть используется для создания защищенного типа прокси-объекта для списка интерфейсов не требуя предварительного поколения прокси-класса. Динамический прокси классы полезны для приложения или библиотеки, которые необходимо предоставить тип-безопасная отражательная рассылка вызовов на объекты, которые присутствуют API интерфейса.

Динамические прокси-классы

Ответ 3

Я просто придумал интересное использование для динамического прокси.

У нас были некоторые проблемы с некритической службой, которая связана с другой зависимой службой и хотела изучить способы отказоустойчивости, когда эта зависимая служба становится недоступной.

Итак, я написал LoadSheddingProxy, который принимает два делегата - один из них - это удаленный вызов для "нормальной" службы (после поиска JNDI). Другим объектом является 'dummy' load-shedding impl. Существует простая логика, окружающая каждый метод invoke, который улавливает таймауты и переадресации на фикцию в течение определенного периода времени перед повторной попыткой. Вот как я его использую:

// 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 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();
        }
    }
}

И здесь прокси:

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;
}
}

Ответ 4

Класс java.lang.reflect.Proxy позволяет динамически реализовывать интерфейсы, обрабатывая вызовы методов в InvocationHandler. Он считается частью средства отражения Java, но не имеет никакого отношения к генерации байт-кода.

Sun учебник об использовании класса Proxy. Google также помогает.

Ответ 5

Один из вариантов использования - спящий режим - он предоставляет вам объекты, реализующие интерфейс классов модели, но при использовании getters и seters существует код, связанный с db. То есть вы используете их, как если бы они были просто POJO, но на самом деле многое происходит под прикрытием.

Например, вы просто вызываете получателя лениво загруженного свойства, но на самом деле свойство (возможно, целая большая структура объекта) извлекается из базы данных.

Для получения дополнительной информации вы должны проверить cglib.