Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / Вопрос по proxy-классам. / 18 сообщений из 18, страница 1 из 1
19.02.2016, 12:05
    #39175141
ll13
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
Добрый день.
Изучаю java по книге "Java. Библиотека профессионала Хорстманн, Корнелл"
в книге приведен пример трассировки вызова методов объекта используя прокси-класс.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
import java.lang.reflect.*;
import java.util.*;

class TraceHandler implements InvocationHandler{
    
    private Object target;
    
    public TraceHandler(Object target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                
        System.out.print(target);
        System.out.print("." + method.getName() + "(");
        if(args != null){
            for (int i = 0; i < args.length; i++) {
                System.out.print(args[i]);
                if(i < args.length - 1)
                    System.out.print(", ");
            }
        }
        System.out.println(")");
        
        return method.invoke(target, args);         
        
    }
}

public class ProxyTest {

    public static void main(String[] args) {
        
        Object[] elements = new Object[1000];
        for (int i = 0; i < elements.length; i++) {
            Integer value = i + 1;
            InvocationHandler handler = new TraceHandler(value);
            Object proxy = Proxy.newProxyInstance(null , new Class[] {Comparable.class}, handler);
            elements[i] = proxy;
        }
        
        Integer key = new Random().nextInt(elements.length) + 1;
        
        int result = Arrays.binarySearch(elements, key);
   
    }
    
}



Пример полностью рабочий.
Это работает:
Код: java
1.
Arrays.binarySearch(elements, key);


но почему в таком случае не работает?!
Код: java
1.
Arrays.sort(elements);



Выдаются ошибки:
Код: plaintext
1.
2.
3.
4.
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
	at com.sun.proxy.$Proxy0.compareTo(Unknown Source)
	at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320)
	at java.util.ComparableTimSort.sort(ComparableTimSort.java:202)
...
Рейтинг: 0 / 0
19.02.2016, 13:28
    #39175247
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
ll13,

Научитесь читать исключения. Исключение, которое указывает на проблему следующее:
Код: java
1.
2.
3.
Caused by: java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to java.lang.Integer
        at java.lang.Integer.compareTo(Unknown Source)
        ... 10 more


А не то что вы привели.

Объяснять надо исключение или понятно?
...
Рейтинг: 0 / 0
19.02.2016, 13:51
    #39175277
Garrick
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
Blazkowiczll13,

Научитесь читать исключения. Исключение, которое указывает на проблему следующее:
Код: java
1.
2.
3.
Caused by: java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to java.lang.Integer
        at java.lang.Integer.compareTo(Unknown Source)
        ... 10 more


А не то что вы привели.

И более того, оно даже указывает имя класса и номер строки где возникла проблема.
...
Рейтинг: 0 / 0
19.02.2016, 15:18
    #39175363
ll13
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
Garrick, Blazkowicz

Насколько я понимаю исключение вызвано невозможностью приведения типа com.sun.proxy.$Proxy0 к java.lang.Integer
Но я никак не могу понять что привело к данной ситуации? Как локализовать и исправить ошибку?
...
Рейтинг: 0 / 0
19.02.2016, 15:27
    #39175375
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
ll13Но я никак не могу понять что привело к данной ситуации? Как локализовать и исправить ошибку?
Это очень грустно слышать.
У вас есть массив Proxy. Для сортировки нужно сравнивать разные элементы коллекции друг с другом.
Для сравнения вызывается метод Comparable.compareTo(). То есть у экземпляра Proxy вызывается метод compareTo и аргументом метода передаётся другой Proxy.
InvocationHandler перехватывает вызов, чего-то там логирует и вызывает метод делегата (у вас о почему-то target).
В target у вас хранится Integer, значит method.invoke(target, args); вызывает Integer.compareTo(args)
В args у вас Proxy. А Integer.compareTo() ожидает только Integer.

Зачем у вас переменные типа Object для хранения Integer это вопрос открытый.
...
Рейтинг: 0 / 0
19.02.2016, 15:59
    #39175413
ll13
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
BlazkowiczУ вас есть массив Proxy. Для сортировки нужно сравнивать разные элементы коллекции друг с другом.
Для сравнения вызывается метод Comparable.compareTo(). То есть у экземпляра Proxy вызывается метод compareTo и аргументом метода передаётся другой Proxy.
InvocationHandler перехватывает вызов, чего-то там логирует и вызывает метод делегата (у вас о почему-то target).
В target у вас хранится Integer, значит method.invoke(target, args); вызывает Integer.compareTo(args)
В args у вас Proxy. А Integer.compareTo() ожидает только Integer.
Спасибо, проблему понял...
Каким образом можно "правильно" реализовать подобную логику логирования? Где можно посмотреть корректный пример?
Зачем у вас переменные типа Object для хранения Integer это вопрос открытый.
Вопрос этот не ко мне а к авторам книги "Java. Библиотека профессионала Хорстманн, Корнелл"
Пишу ещё раз: Изучаю java по книге "Java. Библиотека профессионала Хорстманн, Корнелл"...
...
Рейтинг: 0 / 0
19.02.2016, 16:07
    #39175421
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
ll13,

Логирование реализовано правильно. Не правильно реализовано делегирования вызова для метода compareTo.
...
Рейтинг: 0 / 0
19.02.2016, 16:17
    #39175434
ll13
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
Blazkowiczll13,

Логирование реализовано правильно. Не правильно реализовано делегирования вызова для метода compareTo.

Где можно посмотреть пример правильной реализации делегирования?
...
Рейтинг: 0 / 0
19.02.2016, 16:43
    #39175454
ll13
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
Подводя итог по данному вопросу:
1). Есть интерфейс Comparable(содержит один метод compareTo)
2). Есть класс Integer, реализующий данный интерфейс.
3). Есть прокси-класс, перехватывающий данный метод.
3). Каким образом можно правильно организовать вызов данного метода, т.е. method.invoke(...) из прокси-класса?
...
Рейтинг: 0 / 0
19.02.2016, 16:52
    #39175469
0FD
0FD
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
ll13,

Код: java
1.
return -method.invoke(args[0],target); 
...
Рейтинг: 0 / 0
19.02.2016, 17:04
    #39175483
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
ll13Где можно посмотреть пример правильной реализации делегирования?


Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
for(int i = 0; i < args.length; i++){
   Object arg = args[i];
   if(arg != null && Proxy.isProxyClass(arg.getClass()){
      TraceHandler handler = (TraceHandler) Proxy.getInvocationHandler(arg);     
      args[i] = handler.target;
   }
}

return method.invoke(target, args);  
...
Рейтинг: 0 / 0
19.02.2016, 17:05
    #39175485
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
0FDll13,

Код: java
1.
return -method.invoke(args[0],target); 


Зачетный трюк.
...
Рейтинг: 0 / 0
19.02.2016, 17:06
    #39175487
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
ll13Подводя итог по данному вопросу:
1). Есть интерфейс Comparable(содержит один метод compareTo)
2). Есть класс Integer, реализующий данный интерфейс.
3). Есть прокси-класс, перехватывающий данный метод.
3). Каким образом можно правильно организовать вызов данного метода, т.е. method.invoke(...) из прокси-класса?

Проблема в аргументе. Это понятно?
...
Рейтинг: 0 / 0
19.02.2016, 17:06
    #39175488
ll13
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
0FDll13,

Код: java
1.
return -method.invoke(args[0],target); 



Ошибка:
Uncompilable source code - bad operand type java.lang.Object for unary operator '---'

Даже если бы это сработало, проблемы это не решает. Это всего лишь пример, с помощью которого я пытаюсь понять как работает этот механизм.
А если у интерфейса будет 1000 методов... то для каждого персональные условия для invoke писать ?! Более того интерфейсы которые требуется перехватывать могут определяться в процессе работы программы и неизвестны на этапе компиляции.
Тогда какой смысл в прокси?
Насколько я понял, динамические прокси-классы нужны для того, что бы перехватить обращение к методам заранее неизвестного интерфейса(ов), выполнить некие дополнительные действия, например логирование, как в данном примере, а затем вызвать требуемый метод объекта.
Или я чего-то недопонимаю....?
...
Рейтинг: 0 / 0
19.02.2016, 17:15
    #39175494
0FD
0FD
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
ll13,

Ну конечно, возвращается Integer. -((Integer)m.invoke).intValue()
У method есть имя getName(), обрабатываете только нужные, например if(method.getName().equals("compareTo")), остальные method.invoke(...)
...
Рейтинг: 0 / 0
19.02.2016, 17:16
    #39175496
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
ll13Ошибка:
Uncompilable source code - bad operand type java.lang.Object for unary operator '---'

Вы слишком рано задаёте вопросы про прокси, если банально ещё ни синтаксис не освоили, ни вообще не понимаете код в примере из книги.

ll13Даже если бы это сработало, проблемы это не решает. Это всего лишь пример, с помощью которого я пытаюсь понять как работает этот механизм.

минус уберите и сработает.

ll13А если у интерфейса будет 1000 методов... то для каждого персональные условия для invoke писать ?! Более того интерфейсы которые требуется перехватывать могут определяться в процессе работы программы и неизвестны на этапе компиляции.

Ну, просто здесь такой вот особый пример. Проблема не в прокси, а в том что у вас массив прокси. И если вы создаёте массив прокси и пытаетесь сравнивать прокси с прокси, вы должны понимать последствия.
Конечно, отчасти это ещё и связано с реализацией именно Java Proxy. Существуют другие способы создать прокси. У них подобной проблемы не будет.

ll13Тогда какой смысл в прокси?

Есть такой термин - Aspect-Oriented Programming.

ll13Насколько я понял, динамические прокси-классы нужны для того, что бы перехватить обращение к методам

Угу.

ll13заранее неизвестного интерфейса(ов),

Смешно, да. В методе Proxy.newProxyInstance() где там неизвестные интерфейсы?

ll13выполнить некие дополнительные действия, например логирование, как в данном примере, а затем вызвать требуемый метод объекта. Или я чего-то недопонимаю....?
Всё верно. Задумка такая. Но есть теория, а есть практика. И практика зачастую накладывает ряд ограничений. Это надо понимать.
...
Рейтинг: 0 / 0
19.02.2016, 18:04
    #39175536
ll13
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
Спасибо! это рабочий код, буду разбираться дальше.

Blazkowicz
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
for(int i = 0; i < args.length; i++){
   Object arg = args[i];
   if(arg != null && Proxy.isProxyClass(arg.getClass()){
      TraceHandler handler = (TraceHandler) Proxy.getInvocationHandler(arg);     
      args[i] = handler.target;
   }
}

return method.invoke(target, args);  



BlazkowiczСмешно, да. В методе Proxy.newProxyInstance() где там неизвестные интерфейсы?

Ну например можно так:
Код: java
1.
Object proxy = Proxy.newProxyInstance(null , Class.forName("НеизвестныйЗаранееКласс").getInterfaces(), handler);
...
Рейтинг: 0 / 0
19.02.2016, 18:47
    #39175561
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос по proxy-классам.
ll13Ну например можно так:
Код: java
1.
Object proxy = Proxy.newProxyInstance(null , Class.forName("НеизвестныйЗаранееКласс").getInterfaces(), handler);



:) В общем, для логирования и подобных AOP решений, JDK Proxy никто не использует. Он подходит только для каких-то простых реализаций, чтобы сделать фасад и перехватывать вызовы к определенному интерфейсу.

Более глобальные вещи реализуют через AOP библиотеки типа Aspect4j.
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / Вопрос по proxy-классам. / 18 сообщений из 18, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]