В чем разница между java Dynami c proxy и plain java class? - PullRequest
0 голосов
/ 23 января 2020

Прокси-сервер используется для перехвата ИЛИ для замены ИЛИ изменения существующей функциональности целевого объекта без его изменения, но мы можем добиться того же, используя обычный класс java, унаследовав целевой класс и переопределив его методы.
Тогда каково его точное использование? Чем он отличается от обычного java класса?

Ответы [ 4 ]

3 голосов
/ 23 января 2020

Прокси - это просто имя, данное классу в соответствии с шаблоном проектирования прокси. Это нормальный java класс.

. Для дальнейшего чтения отметьте Шаблон прокси в Java

1 голос
/ 24 января 2020

Вы можете реализовать прокси с обычными классами, например,

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

Преимущество генераторов прокси-серверов Dynami c, таких как java.lang.reflect.Proxy, заключается в том, что они позволяют обрабатывать произвольное число интерфейсов. методы с одним методом-обработчиком и не требуют жесткого кодирования интерфейсов для реализации. Интерфейсы даже не должны существовать во время компиляции.

Например:

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

Это демонстрирует, как один метод-обработчик может украшать интерфейс List двумя дюжина методов и динамическое декорирование возвращаемых значений, когда типом возврата является интерфейс, украшающий четыре интерфейса в примере кода, и он будет декорировать больше при изменении тестового примера.

Просто попробуйте реализовать это с помощью обычных реализаций эти интерфейсы, и вы сразу же поймете преимущество генератора прокси Dynami c. Не говоря уже о возможности адаптации к новым интерфейсам при появлении…


Другим вариантом использования будет динамическое связывание компонентов c. Это может выглядеть так:

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]]

Уже есть java.beans.EventHandler, предоставляющий именно эту функцию для общего случая использования установки свойства другого компонента в ответ на событие.

0 голосов
/ 23 января 2020

Термин «Прокси» является расплывчатым, но если вы спрашиваете о Java Dynami c Прокси, они создаются во время выполнения, поэтому они предоставляют множество гибких возможностей.

Существует множество способов создания прокси:

  • с использованием java.lang.reflect.InvocationHandler
  • с использованием таких библиотек, как cglib, bytebuddy, jassist, asm et c
0 голосов
/ 23 января 2020

Прокси-класс - это класс, который работает как интерфейс для другого класса или группы классов.

Его можно рассматривать как Smart Interface

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

Один из самых популярных примеров Прокси-шаблон можно найти в автоматизации тестирования браузера.

Пример использования шаблона прокси

Предположим, что есть 3 объекта браузера, определенных 3 различными классами - InternetExplorer, Firefox, Chrome.

Если требуется запустить тестовый пример в браузере, выбранном во время выполнения, тогда может помочь шаблон Proxy .

Прокси-класс с именем 'Browser', который принимает ' Имя браузера »в качестве входных данных и создания экземпляра нужного браузера во время выполнения может быть отличным решением в этом сценарии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...